home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc International / Development / TSMTEsample⁄1.1 / Source / SamplePart.cpp < prev    next >
Encoding:
Text File  |  1996-11-14  |  113.7 KB  |  3,531 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2.  
  3.     File:            SamplePart.cpp
  4.     
  5.     Written by:        Steve Smith
  6.     
  7.     Copyright:        © 1995 by Apple Computer, Inc., all rights reserved.
  8.     
  9.     Description:    SamplePart demonstrates the most basic functions and
  10.                     responsibilities of an OpenDoc™ leaf part.
  11.     
  12.     
  13.     Demonstrates:    The following recipes were used in implementing the
  14.                     SamplePart:
  15.                      1. Open
  16.                      2. Adding A Display Frame
  17.                      3. Adding A Facet
  18.                      4. Part Drawing
  19.                      5. Refcounting Geometry
  20.                      6. ViewTypes & Presentations
  21.                      7. Display Frame 'ternalization
  22.                      8. Part Init & Externalization
  23.                      9. Part Init & partWrapper
  24.                     10. Part Storage Model
  25.                     11. Persistent Reference
  26.                     12. RefCounting
  27.                     13. Storage Unit
  28.                     14. Activation
  29.                     15. Basic Event Handling
  30.                     16. Menus
  31.                     17. Windows & Dialogs
  32.                     18. Exception Handling
  33.                     19. Memory Manager
  34.                     20. Using Resources
  35.                     21. Lazy Frame Internalization
  36.                     22. Multiple Kind Support
  37.     
  38.     
  39.     Notes:            • For methods where it is necessary to call the parent class
  40.                     implementation, the calls are made from the SOM class. See
  41.                     som_SamplePart.cpp and the Class Reference to know whether
  42.                     you need to call the parent class from any method.                    
  43.     
  44. ------------------------------------------------------------------------------*/
  45.  
  46. // -- Compiler/Preprocessor Switches --
  47.  
  48. #ifndef _COMPILERDEFS_
  49. #include "CompDefs.h"
  50. #endif
  51.  
  52. // -- OpenDoc Utilities --
  53.  
  54. #ifndef _EXCEPT_
  55. // Exceptions define several important macros (eg. CHECKENV)
  56. // which are used in the SOM method dispatch glue. If Except.h
  57. // is not included early enough, exceptions may not be thrown
  58. // correctly when returning from a SOM method with the "ev" parameter set.
  59. #include <Except.h>
  60. #endif
  61.  
  62. // -- SamplePart Includes --
  63.  
  64. #ifndef _SAMPLEPARTGLOBALS_
  65. #include "SamplePartGlobals.h"
  66. #endif
  67.  
  68. #ifndef _SAMPLEPARTDEF_
  69. #include "SamplePartDef.h"
  70. #endif
  71.  
  72. #ifndef _SAMPLEPARTUTILS_
  73. #include "SamplePartUtils.h"
  74. #endif
  75.  
  76. #ifndef _SAMPLEPART_
  77. #include "SamplePart.h"
  78. #endif
  79.  
  80. #ifndef _SAMPLECOLLECTIONS_
  81. #include "SampleCollections.h"
  82. #endif
  83.  
  84. #ifndef _TEMPFOCUS_
  85. #include "TempFocus.h"
  86. #endif
  87.  
  88. // -- OpenDoc Includes --
  89.  
  90. #ifndef _ODTYPES_
  91. #include <ODTypes.h>
  92. #endif
  93.  
  94. #ifndef SOM_ODPart_xh
  95. #include <Part.xh>
  96. #endif
  97.  
  98. #ifndef SOM_ODFacet_xh
  99. #include <Facet.xh>
  100. #endif
  101.  
  102. #ifndef SOM_ODFrame_xh
  103. #include <Frame.xh>
  104. #endif
  105.  
  106. #ifndef SOM_ODFrameFacetIterator_xh
  107. #include <FrFaItr.xh>
  108. #endif
  109.  
  110. #ifndef SOM_ODArbitrator_xh
  111. #include <Arbitrat.xh>
  112. #endif
  113.  
  114. #ifndef SOM_Module_OpenDoc_Foci_defined
  115. #include <Foci.xh>
  116. #endif
  117.  
  118. #ifndef SOM_ODShape_xh
  119. #include <Shape.xh>
  120. #endif
  121.  
  122. #ifndef SOM_Module_OpenDoc_StdProps_defined
  123. #include <StdProps.xh>
  124. #endif
  125.  
  126. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  127. #include <StdTypes.xh>
  128. #endif
  129.  
  130. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  131. #include <StdDefs.xh>
  132. #endif
  133.  
  134. #ifndef SOM_Module_OpenDoc_Commands_defined
  135. #include <CmdDefs.xh>
  136. #endif
  137.  
  138. #ifndef SOM_ODDraft_xh
  139. #include <Draft.xh>
  140. #endif
  141.  
  142. #ifndef SOM_ODStorageUnit_xh
  143. #include <StorageU.xh>
  144. #endif
  145.  
  146. #ifndef SOM_ODStorageUnitView_xh
  147. #include <SUView.xh>
  148. #endif
  149.  
  150. #ifndef SOM_ODTransform_xh
  151. #include <Trnsform.xh>
  152. #endif
  153.  
  154. #ifndef SOM_ODFocusSet_xh
  155. #include <FocusSet.xh>
  156. #endif
  157.  
  158. #ifndef SOM_ODMenuBar_xh
  159. #include <MenuBar.xh>
  160. #endif
  161.  
  162. #ifndef SOM_ODWindow_xh
  163. #include <Window.xh>
  164. #endif
  165.  
  166. #ifndef SOM_ODWindowState_xh
  167. #include <WinStat.xh>
  168. #endif
  169.  
  170. #ifndef SOM_ODCanvas_xh
  171. #include <Canvas.xh>
  172. #endif
  173.  
  174. #ifndef SOM_ODSession_xh
  175. #include <ODSessn.xh>
  176. #endif
  177.  
  178. // -- OpenDoc Utilities --
  179.  
  180. #ifndef _ITEXT_
  181. #include <IText.h>
  182. #endif
  183.  
  184. #ifndef _FOCUSLIB_
  185. #include <FocusLib.h>
  186. #endif
  187.  
  188. #ifndef _BNDNSUTL_
  189. #include <BndNSUtl.h>
  190. #endif
  191.  
  192. #ifndef _DLOGUTIL_
  193. #include <DlogUtil.h>
  194. #endif
  195.  
  196. #ifndef _ISOSTR_
  197. #include <ISOStr.h>
  198. #endif
  199.  
  200. #ifndef _ODDEBUG_
  201. #include <ODDebug.h>
  202. #endif
  203.  
  204. #ifndef _ODMEMORY_
  205. #include <ODMemory.h>
  206. #endif
  207.  
  208. #ifndef _ODUTILS_
  209. #include <ODUtils.h>
  210. #endif
  211.  
  212. #ifndef _STORUTIL_
  213. #include <StorUtil.h>
  214. #endif
  215.  
  216. #ifndef _STDTYPIO_
  217. #include <StdTypIO.h>
  218. #endif
  219.  
  220. #ifndef _TEMPITER_
  221. #include <TempIter.h>
  222. #endif
  223.  
  224. #ifndef _TEMPOBJ_
  225. #include <TempObj.h>
  226. #endif
  227.  
  228. #ifndef _USERSRCM_
  229. #include <UseRsrcM.h>
  230. #endif
  231.  
  232. #ifndef _WINUTILS_
  233. #include <WinUtils.h>
  234. #endif
  235.  
  236. // -- Macintosh Includes --
  237.  
  238. #ifndef __ERRORS__
  239. #include <Errors.h>
  240. #endif
  241.  
  242. #ifndef __RESOURCES__
  243. #include <Resources.h>
  244. #endif
  245.  
  246. #ifndef __DIALOGS__
  247. #include <Dialogs.h>
  248. #endif
  249.  
  250. #ifndef __TOOLUTILS__
  251. #include <ToolUtils.h>
  252. #endif
  253.  
  254. #ifndef __ICONS__
  255. #include <Icons.h>
  256. #endif
  257.  
  258. #ifndef __QUICKDRAW__
  259. #include <Quickdraw.h>
  260. #endif
  261.  
  262. #ifndef __GXMATH__
  263. #include <GXMath.h>
  264. #endif
  265.  
  266. #ifndef __DRAG__
  267. #include <Drag.h>
  268. #endif
  269.  
  270. //ForTSMTE
  271. #ifndef __tsmUtl__    
  272. #include "tsmUtl.h"
  273. #endif
  274.  
  275. #pragma segment SamplePart
  276.  
  277. //==============================================================================
  278. // SamplePart
  279. //==============================================================================
  280.  
  281. //------------------------------------------------------------------------------
  282. // Method:        Constructor
  283. // Origin:        SamplePart
  284. //
  285. // Description:    This is the C++ class constructor.
  286. //
  287. // Warnings:    You are not allowed to throw an exception from this method.
  288. //------------------------------------------------------------------------------
  289.  
  290. SamplePart::SamplePart()
  291. {
  292.     SOM_Trace("SamplePart","Constructor");
  293.     
  294.     fDisplayFrames        = kODNULL;
  295.     fDirty                = kODFalse;
  296.     fSelf                = kODNULL;
  297.     fReadOnlyStorage    = kODFalse;
  298.     
  299.     fGlobalsInited        = kODFalse;
  300. }
  301.  
  302. //------------------------------------------------------------------------------
  303. // Method:        Destructor
  304. // Origin:        SamplePart
  305. //
  306. // Description:    This is the C++ class destructor.
  307. //
  308. // Warnings:    You are not allowed to throw an exception from this method.
  309. //------------------------------------------------------------------------------
  310.  
  311. SamplePart::~SamplePart()
  312. {
  313.     SOM_Trace("SamplePart","Destructor");
  314. }
  315.  
  316. //==============================================================================
  317. #pragma mark    • Initialization •
  318. //==============================================================================
  319.  
  320. //------------------------------------------------------------------------------
  321. // Method:        InitPart
  322. // Origin:        ODPart
  323. //
  324. // Description:    This method is called when a new instance of this part is being
  325. //                created. The part should prepare itself to run.
  326. //
  327. // Parent:        The part's parent class was called before this method was
  328. //                dispatched to (see som_SamplePart.cpp).
  329. //
  330. // Warning:        It is not appropriate to require user interaction while
  331. //                stationery is being created. Do not present the user with error
  332. //                dialogs or splash screens from this method.
  333. //------------------------------------------------------------------------------
  334.  
  335. void SamplePart::InitPart( Environment*        ev,
  336.                            ODStorageUnit*    storageUnit,
  337.                            ODPart*            partWrapper )
  338. {
  339.     SOM_Trace("SamplePart","InitPart");
  340.  
  341.     TRY
  342.         // To allow editor swapping (translation) at runtime, OpenDoc requires
  343.         // that we pass in a "reference" to ourselves when interacting with the
  344.         // API (eg. WindowState::RegisterWindow(), Dispatcher::RegisterIdle, etc).
  345.         // The "partWrapper" passed to us here and in InitPartFromStorage is the
  346.         // "reference" OpenDoc is asking us to use.
  347.         fSelf = partWrapper;
  348.     
  349.         // We are being created, either as part of generating stationery or
  350.         // by some editor instantiating the part, so the destination storage
  351.         // must be writeable.
  352.         fReadOnlyStorage = kODFalse;
  353.             
  354.         // Call the common initialization code to get set up.
  355.         this->Initialize(ev);
  356.  
  357.         // Since we have just been created, our state/content info has
  358.         // never been written out, so setting our "dirty" flag will
  359.         // give us a chance to do that.
  360.         this->SetDirty(ev);
  361.     
  362.     CATCH_ALL
  363.         // Clean up will occur in the destructor which will be called
  364.         // shortly after we return the error.
  365.         RERAISE;
  366.     ENDTRY
  367. }
  368.  
  369. //------------------------------------------------------------------------------
  370. // Method:        InitPartFromStorage
  371. // Origin:        ODPart
  372. //
  373. // Description:    This method is called when a document/stationery is being opened
  374. //                or when the part is internalized by its containing part. The
  375. //                part should merely read in the saved state/content and
  376. //                initialize itself. The part must not alter its storage unit;
  377. //                otherwise, the "Save" menu item becomes enabled without the user
  378. //                actually having made a change to the document.
  379. //
  380. // Parent:        The part's parent class was called before this method was
  381. //                dispatched to (see som_SamplePart.cpp).
  382. //------------------------------------------------------------------------------
  383.  
  384. void SamplePart::InitPartFromStorage( Environment*        ev,
  385.                                       ODStorageUnit*    storageUnit,
  386.                                       ODPart*            partWrapper )
  387. {
  388.     SOM_Trace("SamplePart","InitPartFromStorage");
  389.  
  390.     TRY
  391.         // To allow editor swapping (translation) at runtime, OpenDoc requires
  392.         // that we pass in a "reference" to ourselves when interacting with the
  393.         // API (eg. WindowState::RegisterWindow(), Dispatcher::RegisterIdle, etc).
  394.         // The "partWrapper" passed to us here and in InitPart is the
  395.         // "reference" OpenDoc is asking us to use.
  396.         fSelf = partWrapper;
  397.             
  398.         // Are we being opened from a read-only draft? If so, we cannot
  399.         // write anything back out to our storage unit.
  400.         fReadOnlyStorage = ( ODGetDraft(ev,storageUnit)->
  401.                                 GetPermissions(ev) < kODDPSharedWrite );
  402.             
  403.         // Call the common initialization code to get set up.
  404.         this->Initialize(ev);
  405.     
  406.         // Read in the state the part was in when it was last Externalized.
  407.         // This allows the part to present the same "environment" the user
  408.         // had the part set up in the last time it was edited.
  409.         this->InternalizeStateInfo(ev, storageUnit);
  410.     
  411.         // Read in the contents for your part editor.
  412.         this->InternalizeContent(ev, storageUnit);
  413.  
  414.     CATCH_ALL
  415.         // Clean up will occur in the destructor which will be called
  416.         // shortly after we return the error.
  417.         RERAISE;
  418.     ENDTRY
  419. }
  420.  
  421. //------------------------------------------------------------------------------
  422. // Method:        Initialize
  423. // Origin:        SamplePart
  424. //
  425. // Description:    This method is called during the initialization of the part. The
  426. //                method is used to initialize all fields of the part and to
  427. //                convert ISO types to tokens for faster comparisons throughout
  428. //                the code.
  429. //
  430. //                If an exception is thrown in this method, it wil be propogated
  431. //                back to OpenDoc which will call our ReleaseAll() method and the
  432. //                class destructor. All memory allocated here will be cleaned up
  433. //                in the ReleaseAll() method.
  434. //------------------------------------------------------------------------------
  435.  
  436. void SamplePart::Initialize( Environment*    ev )
  437. {
  438.     SOM_Trace("SamplePart","Initialize");
  439.  
  440.     // Grab a reference to the Session object. This is merely for
  441.     // convenience.
  442.     ODSession* session = ODGetSession(ev,fSelf);
  443.             
  444.     // Initialize the Binding Name Space Utilities (new to version 1.1)
  445.     InitBindingNamespaceUtils(session);
  446.  
  447.     // Create a list to keep track of the frames we are being
  448.     // displayed in. Used for part maintenance (ie. Purging memory).
  449.     fDisplayFrames = new CList;
  450.  
  451.     // First check to see if the library's global variables have
  452.     // been initialized (meaning another part instantiation is already
  453.     // running).
  454.  
  455.     if ( gGlobalsUsageCount == 0 )
  456.     {
  457.         // Create our globals space. We store the globals in a struct so
  458.         // that we can put them in temp mem. Otherwise, CFM loads the globals
  459.         // with the data fragment of a CFM library in the application heap.
  460.         gGlobals = new SamplePartGlobals;
  461.     
  462.         // It is required that parts instantiate their menu bars from 
  463.         // the base OpenDoc menu bar. This maintains consistency in the
  464.         // default menu items and their placement.
  465.         // Since the object is a copy, we can add and subtract menus and
  466.         // items without affecting other running parts.
  467.         gGlobals->fMenuBar = session->GetWindowState(ev)->CopyBaseMenuBar(ev);
  468.  
  469.         // We will be using the following foci (shared resources) in this
  470.         // part. For convenience, we tokenize the values here and store
  471.         // them for equivalence tests in the activation methods.
  472.         gGlobals->fSelectionFocus = session->Tokenize(ev, kODSelectionFocus);
  473.         gGlobals->fMenuFocus = session->Tokenize(ev, kODMenuFocus);
  474.         gGlobals->fModalFocus = session->Tokenize(ev, kODModalFocus);
  475.         gGlobals->fKeyFocus = session->Tokenize(ev, kODKeyFocus);    //ForTSMTE
  476.     
  477.         // Also for convenience, we tokenize our part's main presentation
  478.         // and the standard view types.
  479.         gGlobals->fMainPresentation = session->Tokenize(ev, kMainPresentation);
  480.     
  481.         gGlobals->fFrameView = session->Tokenize(ev, kODViewAsFrame);
  482.         gGlobals->fLargeIconView = session->Tokenize(ev, kODViewAsLargeIcon);
  483.         gGlobals->fSmallIconView = session->Tokenize(ev, kODViewAsSmallIcon);
  484.         gGlobals->fThumbnailView = session->Tokenize(ev, kODViewAsThumbnail);
  485.     
  486.         // Lastly, we will package the menu and selection focus
  487.         // so that we can request the "set" at activation time.
  488.         gGlobals->fUIFocusSet = session->GetArbitrator(ev)->CreateFocusSet(ev);
  489.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fMenuFocus);
  490.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fSelectionFocus);
  491.         gGlobals->fUIFocusSet->Add(ev, gGlobals->fKeyFocus);    //ForTSMTE
  492.             
  493.         // Determine what Script/Language the part is localized for.
  494.         // This is important/necessary for creating OpenDoc's text objects.
  495.         GetEditorScriptLanguage(ev, &gGlobals->fEditorsScript, &gGlobals->fEditorsLanguage);
  496.         
  497.         // The first client of the global variables is running.
  498.         gGlobalsUsageCount = 1;
  499.         fGlobalsInited = kODTrue;
  500.     }
  501.     else
  502.     // If the globals have been initialized, we just bump the "usage" count so
  503.     // that we know how many part instances are using them.
  504.     {
  505.         gGlobalsUsageCount++;
  506.         fGlobalsInited = kODTrue;
  507.     }
  508.  
  509.     //ForTSMTE
  510.     fTERec.fText[0]        = 0;
  511.     fTERec.fTEHandle    = kODNULL;
  512.     tsmCheck(&fTERec);            
  513. }
  514.  
  515. //==============================================================================
  516. #pragma mark    • Storage •
  517. //==============================================================================
  518.  
  519. //------------------------------------------------------------------------------
  520. // Method:        Release
  521. // Origin:        ODPart
  522. //
  523. // Description:    This method is called each time an object releases a reference
  524. //                to the part. If the refcount falls to 0, the part should
  525. //                release the fSelf part reference.
  526. //
  527. // Parent:        The part's parent class was called before this method was
  528. //                dispatched to (see som_SamplePart.cpp).
  529. //
  530. // Warning:        If the part releases any other object when the refcount falls to
  531. //                zero, it will need to override the Acquire method so
  532. //                that the object can be referenced again if the parts refcount
  533. //                should be incremented before it is deleted.
  534. //------------------------------------------------------------------------------
  535.  
  536. void SamplePart::Release( Environment* ev )
  537. {
  538.     SOM_Trace("SamplePart","Release");
  539.  
  540.     if ( fSelf->GetRefCount(ev) == 0 )
  541.         ODGetDraft(ev,fSelf)->ReleasePart(ev,fSelf);
  542. }
  543.  
  544. //------------------------------------------------------------------------------
  545. // Method:        ReleaseAll
  546. // Origin:        ODPart
  547. //
  548. // Description:    This method is called just prior to the part being deleted by
  549. //                the Draft. The part must release all references to all
  550. //                refcounted objects it has stored internally; not doing so, will
  551. //                cause an "invalid ref count" exception/error at some later time.
  552. //
  553. // Parent:        The part's parent class will be called after this method
  554. //                returns (see som_SamplePart.cpp).
  555. //------------------------------------------------------------------------------
  556.  
  557. void SamplePart::ReleaseAll( Environment* ev )
  558. {
  559.     SOM_Trace("SamplePart","ReleaseAll");
  560.  
  561.     TRY
  562.         // If the last part instance using the globals is released,
  563.         // we need to clean up and delete the globals.
  564.         
  565.         if ( fGlobalsInited && (--gGlobalsUsageCount == 0) )
  566.         {
  567.             // Release the menubar.
  568.             ODReleaseObject(ev, gGlobals->fMenuBar);
  569.             
  570.             // But first, we need to delete the objects we created
  571.             // and stored in the globals struct.
  572.             ODDeleteObject(gGlobals->fUIFocusSet);
  573.  
  574.             // Release the thumbnail (PICT) resource.
  575.             if ( gGlobals->fThumbnail )
  576.             {
  577.                 ReleaseResource(gGlobals->fThumbnail);
  578.                 gGlobals->fThumbnail = kODNULL;
  579.             }
  580.             
  581.             // Now, clean up the globals struct.
  582.             ODDeleteObject(gGlobals);
  583.         }
  584.     
  585.         // Remove and release our display frames.
  586.         if ( fDisplayFrames )
  587.         {
  588.             CListIterator fiter(fDisplayFrames);
  589.             for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  590.                     fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  591.             {
  592.                 // Delete the proxy object and its contents. The frame's
  593.                 // refcount will be decremented in the proxy destructor.
  594.                 fiter.RemoveCurrent();
  595.                 delete proxy;
  596.             }
  597.         
  598.             // Delete the display frame collection.
  599.             ODDeleteObject(fDisplayFrames);
  600.         }
  601.         
  602.     CATCH_ALL
  603.         // If something goes wrong while we are cleaning up, we must
  604.         // let the Draft now because there may be some refcounted objects
  605.         // which did not get released. Not to mention, possible memory
  606.         // leaks.
  607.         RERAISE;            
  608.     ENDTRY
  609. }
  610.  
  611. //------------------------------------------------------------------------------
  612. // Method:        Purge
  613. // Origin:        ODPart
  614. //
  615. // Description:    This method is called when the OpenDoc requires more memory for
  616. //                allocating objects and just before a part is deleted. The part
  617. //                should free up as much memory as it can.
  618. //
  619. //                The part determines which views are being "used" in its display
  620. //                frames. The resources for the unused view types are then purged.
  621. //------------------------------------------------------------------------------
  622.  
  623. ODSize SamplePart::Purge( Environment*    ev,
  624.                           ODSize        /*size*/ )
  625. {
  626.     SOM_Trace("SamplePart","Purge");
  627.  
  628.     // Purge is called during the creation of stationery. However,
  629.     // we have not created our internal display frames list, so 
  630.     // trying to iterate over it would be fatal.
  631.     if ( fDisplayFrames == kODNULL ) return 0;
  632.     
  633.     ODSize         bytesFreed        = 0;
  634.     ODBoolean    usingThumbnail  = kODFalse;
  635.     
  636.     // Iterate over the frames we are displayed through and determine which
  637.     // view types are currently in use.
  638.     
  639.     CListIterator fiter(fDisplayFrames);
  640.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  641.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  642.     {
  643.         // If the display frame is real (has been "connected" or was "added")
  644.         // get its view type; otherwise, ignore it.
  645.         if ( proxy->FrameIsLoaded(ev) )
  646.         {
  647.             ODTypeToken    frameView = proxy->GetFrame(ev)->GetViewType(ev);
  648.             
  649.             if ( frameView == gGlobals->fThumbnailView )
  650.                 usingThumbnail = kODTrue;
  651.             
  652.             // Release the frame reference, but don't get rid of the
  653.             // proxy object because we're not done with the frame. If
  654.             // all parts release their references the frame will be
  655.             // purged from memory.
  656.             proxy->Purge(ev);
  657.         }
  658.     }
  659.     
  660.     // Based on the usage of the supported view types, free up as much
  661.     // memory as possible.
  662.  
  663.     if ( !usingThumbnail && (gGlobals->fThumbnail != kODNULL) )
  664.     {
  665.         bytesFreed += (ODSize) ODGetHandleSize(gGlobals->fThumbnail);
  666.         ReleaseResource(gGlobals->fThumbnail);
  667.         gGlobals->fThumbnail = kODNULL;
  668.     }
  669.     
  670.     return bytesFreed;
  671. }
  672.  
  673. //------------------------------------------------------------------------------
  674. // Method:        InternalizeStateInfo
  675. // Origin:        SamplePart
  676. //
  677. // Description:    This method is used to read in "state" information for the part.
  678. //                This is information related to the workings of the part editor,
  679. //                not the content.
  680. //
  681. //                The part writes out a list of weak references to its display
  682. //                frames. This allows the part to reuse the same display frames
  683. //                each time the document is opened. Those references are read
  684. //                back in and validated here.
  685. //
  686. // Note:        The function StorageUnitGetValue simplifies the use of
  687. //                ODByteArrary, which is required the StorageUnit interface. Look
  688. //                in StorUtil.h/cpp for an example of using the ODByteArray struct.
  689. //------------------------------------------------------------------------------
  690.  
  691. void SamplePart::InternalizeStateInfo( Environment*        ev,
  692.                                        ODStorageUnit*    storageUnit )
  693. {
  694.     SOM_Trace("SamplePart","InternalizeStateInfo");
  695.  
  696.     ODStorageUnitRef    weakRef;
  697.     ODULong                size;
  698.  
  699.     // Internalize the part's display frame list.
  700.  
  701.     if ( storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) )
  702.     {
  703.         storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined,
  704.                                     kODWeakStorageUnitRefs, 0, kODPosUndefined);
  705.                                     
  706.         size = storageUnit->GetSize(ev);
  707.         storageUnit->SetOffset(ev, 0);    
  708.     
  709.         for ( ODULong offset = 0; offset < size; offset += kODStorageUnitRefSize )
  710.         {    
  711.             TRY    
  712.                 StorageUnitGetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef);
  713.                 
  714.                 if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) )
  715.                 {        
  716.                     // We lazily internalize our display frames, meaning we don't "get"
  717.                     // the frame until we absolutely need it. This reduces the time
  718.                     // to internalize the part and the amount of memory needed.
  719.                     
  720.                     // Convert the reference into a runtime id.
  721.                     ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef);
  722.  
  723.                     // Create a proxy class to support the lazy internalization.
  724.                     CFrameProxy* proxy = new CFrameProxy;
  725.                     proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit));
  726.  
  727.                     // Add the proxy to the display frame collection.
  728.                     fDisplayFrames->Add(proxy);
  729.                 }
  730.             CATCH_ALL
  731.                 // consume exception
  732.             ENDTRY
  733.         }
  734.     }
  735. }
  736.  
  737. //------------------------------------------------------------------------------
  738. // Method:        InternalizeContent
  739. // Origin:        SamplePart
  740. //
  741. // Description:    This method is called during initialization of the part from an
  742. //                existing document. The content of the part should be read in.
  743. //
  744. //                The part has no intrinsic content, so the part does nothing.
  745. //                The method is here for completeness.
  746. //------------------------------------------------------------------------------
  747.  
  748. void SamplePart::InternalizeContent( Environment*        ev,
  749.                                      ODStorageUnit*        /*storageUnit*/ )
  750. {
  751.     SOM_Trace("SamplePart","InternalizeContent");
  752.     
  753. }
  754.  
  755. //------------------------------------------------------------------------------
  756. // Method:        CloneInto
  757. // Origin:        ODPart
  758. //
  759. // Description:    This method is called during cloning, typically during data
  760. //                interchange operations (eg. Cut/Paste). The part should
  761. //                write out its current state and content.
  762. //
  763. // Parent:        The part's parent class was called before this method was
  764. //                dispatched to (see som_SamplePart.cpp).
  765. //------------------------------------------------------------------------------
  766.  
  767. void SamplePart::CloneInto( Environment*        ev,
  768.                             ODDraftKey            key,
  769.                             ODStorageUnit*        destinationSU,
  770.                             ODFrame*            initiatingFrame )
  771. {
  772.     SOM_Trace("SamplePart","CloneInto");
  773.     
  774.     // We must first verify that we've never written to this storage unit.
  775.     // If we have, we should do nothing, otherwise we need to write out
  776.     // the current state of the part content.
  777.     
  778.     if ( destinationSU->Exists(ev, kODPropContents, kSamplePartKind, 0) == kODFalse )
  779.     {
  780.         // Add the properties we need to successfully externalize
  781.         // ourselves into the destination storage unit.
  782.         this->CheckAndAddProperties(ev, destinationSU);
  783.                 
  784.         // Write out the part's state information.
  785.         this->ExternalizeStateInfo(ev, destinationSU, key, initiatingFrame);
  786.             
  787.         // Write out the part's content.
  788.         this->ExternalizeContent(ev, destinationSU, key, initiatingFrame);
  789.     }
  790. }
  791.  
  792. //------------------------------------------------------------------------------
  793. // Method:        Externalize
  794. // Origin:        ODPart
  795. //
  796. // Description:    This method is called when the user saves the document. The part
  797. //                should write out its state and content if changes have occurred
  798. //                and if our storage is writeable.
  799. //
  800. // Parent:        The part's parent class was called before this method was
  801. //                dispatched to (see som_SamplePart.cpp).
  802. //------------------------------------------------------------------------------
  803.  
  804. void SamplePart::Externalize( Environment* ev )
  805. {
  806.     SOM_Trace("SamplePart","Externalize");
  807.  
  808.     TRY
  809.         if ( fDirty && !fReadOnlyStorage )
  810.         {
  811.             // Get our storage unit.
  812.             ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  813.         
  814.             // Verify that the storage unit has the appropriate properties
  815.             // and values to allow us to run. If not, add them.
  816.             this->CheckAndAddProperties(ev, storageUnit);
  817.         
  818.             // Verify that there are no "bogus" values in the Content
  819.             // property.
  820.             this->CleanseContentProperty(ev, storageUnit);
  821.         
  822.             // Write out the part's state information.
  823.             this->ExternalizeStateInfo(ev, storageUnit, kODNULLKey, kODNULL);
  824.                 
  825.             // Write out the part's content.
  826.             this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  827.     
  828.             // Flag our part as no longer being dirty.
  829.             fDirty = kODFalse;
  830.         }
  831.     CATCH_ALL
  832.         // Alert the user of the problem.
  833.         this->DoDialogBox(ev, kODNULL, kErrorBoxID, kErrExternalizeFailed);
  834.         // Change the exception value, so the DocShell doesn't display an
  835.         // error dialog.
  836.         SetErrorCode(kODErrAlreadyNotified);
  837.         // Alert the caller.
  838.         RERAISE;
  839.     ENDTRY
  840. }
  841.  
  842. //------------------------------------------------------------------------------
  843. // Method:        ExternalizeKinds
  844. // Origin:        ODPart
  845. //
  846. // Description:    This method is called when the user wants to save the document
  847. //                with multiple representations of the data. This is especially
  848. //                useful for increasing the portability of documents
  849. //                cross-platform.
  850. //
  851. //                A part should verify each kind is valid, that it exists in
  852. //                the content property in the correct order, and write the data.
  853. //
  854. // Note:        For parts which support only on kind, the code can simplified.
  855. //                In this case, it is not necessary to iterate over the kindset
  856. //                because you must, at least, write your preferred kind. The code
  857. //                is shown this way to better illustrate the recipe; it is not
  858. //                wrong, it just does more than it needs to.
  859. //------------------------------------------------------------------------------
  860.  
  861. void SamplePart::ExternalizeKinds( Environment*        ev,
  862.                                    ODTypeList*        kindset )
  863. {
  864.     if ( !fReadOnlyStorage )
  865.     {
  866.         ODBoolean preferredKindWritten = kODFalse;
  867.         
  868.         // Get our storage unit.
  869.         ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  870.         
  871.         // Verify that the storage unit has the appropriate properties
  872.         // and values to allow us to run. If not, add them.
  873.         this->CheckAndAddProperties(ev, storageUnit);
  874.     
  875.         // Verify that there are no "bogus" values in the Content
  876.         // property.
  877.         this->CleanseContentProperty(ev, storageUnit);
  878.     
  879.         // Iterate over the kindset and write out the content types
  880.         // that we support.
  881.         TempODTypeListIterator tliter(ev, kindset);
  882.         for ( ODType kind = tliter.First(); tliter.IsNotComplete();
  883.                 kind = tliter.Next() )
  884.         {
  885.             // Check to see if this is a kind we support. If so, write it.
  886.             if ( ODISOStrCompare(kind, kSamplePartKind) == 0 )
  887.             {
  888.                 // Write out the part's content.
  889.                 this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  890.                 // This is our preferrend kind so we don't need to write it again.
  891.                 // Part editors with more than one kind need to test each kind
  892.                 // against the preferred kind to make sure it's been written.
  893.                 preferredKindWritten = kODTrue;
  894.             }
  895.         }
  896.     
  897.         // Write out the part's state information.
  898.         this->ExternalizeStateInfo(ev, storageUnit, kODNULLKey, kODNULL);
  899.  
  900.         // Even if the kind set contains no types we support, we must at least
  901.         // write out our current "preferred" kind.
  902.         if ( preferredKindWritten == kODFalse )
  903.         {
  904.             // Write out the part's preferred content kind, which, for SamplePart,
  905.             // is the only kind.
  906.             this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL);
  907.         }
  908.     }
  909. }
  910.  
  911. //------------------------------------------------------------------------------
  912. // Method:        ChangeKind
  913. // Origin:        ODPart
  914. //
  915. // Description:    This method is called when the changes the part's primary kind
  916. //                and/or when the part editor is switched via the Info dialog.
  917. //
  918. //                The editor should record the new "preferred" kind and change the
  919. //                UI, if necessary, to allow editing of that kind. Don't write the
  920. //                properties/values/data until the Externalize is called.
  921. //------------------------------------------------------------------------------
  922.  
  923. void SamplePart::ChangeKind( Environment*    ev,
  924.                              ODType            kind )
  925. {
  926.     // SamplePart only has one kind, but we need to make sure the "Preferred Kind"
  927.     // property has the correct value.
  928.     if ( ODISOStrCompare(kind, kSamplePartKind) == 0 )
  929.     {
  930.         // Get our storage unit.
  931.         ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev);
  932.         
  933.         TRY
  934.             // Write out the users preferred kind.
  935.             ODSetISOStrProp(ev, storageUnit, kODPropPreferredKind, kODISOStr, kSamplePartKind);
  936.             
  937.             // Changing our kind dirties our content.
  938.             this->SetDirty(ev);
  939.             
  940.             // Immediately externalize ourselves in the "new" format.
  941.             this->Externalize(ev);
  942.         CATCH_ALL
  943.             // Remove the property and value if something went wrong.
  944.             ODSURemoveProperty(ev, storageUnit, kODPropPreferredKind);
  945.         ENDTRY
  946.     }
  947.     else
  948.         THROW(kODErrInvalidValueType);
  949. }
  950.  
  951. //------------------------------------------------------------------------------
  952. // Method:        ExternalizeStateInfo
  953. // Origin:        SamplePart
  954. //
  955. // Description:    This method is called during externalization of the part. The
  956. //                current "state" of the part should be written out. This "state"
  957. //                information may be lost during Data Interchange operations, so
  958. //                the part needs to recover gracefully if information is missing
  959. //                or incomplete.
  960. //
  961. // Note:        The function StorageUnitSetValue is a macro which simplifies
  962. //                the use of ODByteArrary, which is required by the StorageUnit
  963. //                interface. Look in StorUtil.h/cpp for an example of using the
  964. //                ODByteArray struct.
  965. //------------------------------------------------------------------------------
  966.  
  967. void SamplePart::ExternalizeStateInfo( Environment*        ev,
  968.                                        ODStorageUnit*    storageUnit,
  969.                                        ODDraftKey        key,
  970.                                        ODFrame*            scopeFrame )
  971. {
  972.     SOM_Trace("SamplePart","ExternalizeStateInfo");
  973.  
  974.     ODStorageUnitRef    weakRef;
  975.     ODID                frameID;
  976.     ODID                scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID );
  977.     ODDraft*            fromDraft = ODGetDraft(ev,fSelf);
  978.     
  979.     // Externalize the part's display frame list.
  980.  
  981.     storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined,
  982.                                 kODWeakStorageUnitRefs, 0, kODPosUndefined);
  983.     
  984.     // Persistent object references are stored in a side table, rather than
  985.     // in the property/value stream. Thus, deleting the contents of a value
  986.     // will not "delete" the references previously written to that value. To
  987.     // completely "delete" all references written to the value, we must
  988.     // remove the value and add it back.
  989.     storageUnit->Remove(ev);
  990.     storageUnit->AddValue(ev, kODWeakStorageUnitRefs);
  991.  
  992.     CListIterator fiter(fDisplayFrames);
  993.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  994.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  995.     {
  996.         // Get the ID of the frame we are going to weakly reference.
  997.         frameID = proxy->GetID();
  998.         
  999.         // If a draft key exists, then we are being cloned to another draft.
  1000.         // We must "weak" clone our display frame and reference the cloned
  1001.         // frame. The part re-uses the frameID variable so there aren't two
  1002.         // different GetWeakStorageUnitRef calls.
  1003.         if ( key )
  1004.             frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID);
  1005.         
  1006.         // Write out weak references to each of the part's display frames.
  1007.         storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef);
  1008.         TRY
  1009.             StorageUnitSetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef);
  1010.         CATCH_ALL
  1011.             // consume the exception
  1012.         ENDTRY
  1013.     }
  1014. }
  1015.  
  1016. //------------------------------------------------------------------------------
  1017. // Method:        ExternalizeContent
  1018. // Origin:        SamplePart
  1019. //
  1020. // Description:    This method is called during exteralization of the part. The
  1021. //                content of the part should be written out.
  1022. //
  1023. //                The part has no intrinsic content, so the part does nothing.
  1024. //                The method is here for completeness.
  1025. //------------------------------------------------------------------------------
  1026.  
  1027. void SamplePart::ExternalizeContent( Environment*        ev,
  1028.                                      ODStorageUnit*        /*storageUnit*/,
  1029.                                      ODDraftKey            /*key*/,
  1030.                                      ODFrame*            /*scopeFrame*/ )
  1031. {
  1032.     SOM_Trace("SamplePart","ExternalizeContent");
  1033.  
  1034.     // You would write out your part's content after focusing to your
  1035.     // content property.
  1036. }
  1037.  
  1038. //------------------------------------------------------------------------------
  1039. // Method:        CleanseContentProperty
  1040. // Origin:        SamplePart
  1041. //
  1042. // Description:    This method is called during exteralization of the part so that
  1043. //                the part can remove any value in the content property
  1044. //                that it cannot "accurately" write to.
  1045. //
  1046. // Note:        "Additional" values will be added to a part's content property
  1047. //                during Drag & Drop operations.
  1048. //------------------------------------------------------------------------------
  1049.  
  1050. void SamplePart::CleanseContentProperty( Environment*        ev,
  1051.                                          ODStorageUnit*        storageUnit )
  1052. {
  1053.     SOM_Trace("SamplePart","CleanseContentProperty");
  1054.  
  1055.     ODULong numValues;
  1056.     ODULong index;
  1057.     
  1058.     storageUnit->Focus(ev, kODPropContents, kODPosUndefined, 
  1059.                             kODNULL, 0, kODPosAll);
  1060.     
  1061.     numValues = storageUnit->CountValues(ev);
  1062.     
  1063.     for (index = numValues; index >= 1; index--)
  1064.     {
  1065.         // Index from 1 to n through the values.
  1066.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined, 
  1067.                                 kODNULL, index, kODPosUndefined);
  1068.                                 
  1069.         // Get the ISO type name for the value. The temp object
  1070.         // will automatically delete the returned value when this
  1071.         // scope is exited.
  1072.         TempODValueType value = storageUnit->GetType(ev);
  1073.         
  1074.         // If the value type is not one we support, remove it.
  1075.         if ( ODISOStrCompare(value, kSamplePartKind) != 0 )
  1076.             storageUnit->Remove(ev);
  1077.     }
  1078. }
  1079.  
  1080. //------------------------------------------------------------------------------
  1081. // Method:        CheckAndAddProperties
  1082. // Origin:        SamplePart
  1083. //
  1084. // Description:    This method is called during externalization of the part to
  1085. //                verify that all the properties needed to persistently represent
  1086. //                the current running state of the part.
  1087. //
  1088. //                The part adds the default content property, a preferred editor
  1089. //                property (to aid in part binding), and a display frames
  1090. //                property.
  1091. //
  1092. // Note:        The function StorageUnitSetValue is a macro which simplifies
  1093. //                the use of ODByteArrary, which is required the StorageUnit
  1094. //                interface. Look in StorUtil.h/cpp for an example of using the
  1095. //                ODByteArray struct.
  1096. //------------------------------------------------------------------------------
  1097.  
  1098. void SamplePart::CheckAndAddProperties( Environment*    ev,
  1099.                                         ODStorageUnit*    storageUnit )
  1100. {
  1101.     SOM_Trace("SamplePart","CheckAndAddProperties");
  1102.  
  1103.     // Create our content property and preferred content property kind.
  1104.  
  1105.     if ( !storageUnit->Exists(ev, kODPropContents, kODNULL, 0) )
  1106.         storageUnit->AddProperty(ev, kODPropContents);
  1107.     if ( !storageUnit->Exists(ev, kODPropContents, kSamplePartKind, 0) )
  1108.     {    
  1109.         storageUnit->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll);
  1110.         storageUnit->AddValue(ev, kSamplePartKind);
  1111.     }
  1112.  
  1113.     // Since we are setting up the preferred kind property, we just write
  1114.     // out our default "kind" for the editor. We can write out the user
  1115.     // chosen kind in the ExternalizeStateInfo method.
  1116.  
  1117.     if ( !storageUnit->Exists(ev, kODPropPreferredKind, kODISOStr, 0) )
  1118.     {
  1119.         TRY
  1120.             ODSetISOStrProp(ev, storageUnit, kODPropPreferredKind, kODISOStr, kSamplePartKind);
  1121.         CATCH_ALL
  1122.             // Remove the property and value if something went wrong.
  1123.             ODSURemoveProperty(ev, storageUnit, kODPropPreferredKind);
  1124.         ENDTRY
  1125.     }
  1126.         
  1127.     // Add our display frame list.
  1128.     
  1129.     if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODNULL, 0) )
  1130.         storageUnit->AddProperty(ev, kODPropDisplayFrames);
  1131.     if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) )
  1132.     {
  1133.         storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined, kODNULL, 0, kODPosAll);
  1134.         storageUnit->AddValue(ev, kODWeakStorageUnitRefs);
  1135.     }
  1136. }
  1137.  
  1138. //------------------------------------------------------------------------------
  1139. // Method:        SetDirty
  1140. // Origin:        SamplePart
  1141. //
  1142. // Description:    This method is called by the part when the content or state of
  1143. //                the part has been modified by the user and the "Save" menu item
  1144. //                should be enabled.
  1145. //------------------------------------------------------------------------------
  1146.  
  1147. void SamplePart::SetDirty( Environment*    ev )
  1148. {
  1149.     SOM_Trace("SamplePart","SetDirty");
  1150.  
  1151.     // There is no need to repeatedly tell the draft we have changed;
  1152.     // once is sufficient.
  1153.     if ( !fDirty && !fReadOnlyStorage )
  1154.     {
  1155.         fDirty = kODTrue;
  1156.         ODGetDraft(ev,fSelf)->SetChangedFromPrev(ev);
  1157.     }
  1158. }
  1159.  
  1160. //------------------------------------------------------------------------------
  1161. // Method:        ReadPartInfo
  1162. // Origin:        ODPart
  1163. //
  1164. // Description:    When a frame is being internalized by the Draft, it will ask the
  1165. //                owner (part) to read in its info annotation on the frame.
  1166. //
  1167. //                The part uses a C++ helper class to encapsulate the information
  1168. //                we store with each frame, so we let it internalize itself from
  1169. //                the storage unit view.
  1170. //------------------------------------------------------------------------------
  1171.  
  1172. ODInfoType SamplePart::ReadPartInfo( Environment*        ev,
  1173.                                      ODFrame*            frame,
  1174.                                      ODStorageUnitView*    storageUnitView )
  1175. {
  1176.     SOM_Trace("SamplePart","ReadPartInfo");
  1177.  
  1178.     CFrameInfo* frameInfo = new CFrameInfo(ODGetSession(ev,fSelf));
  1179.         
  1180.     TRY
  1181.         // Ask the info class to internalize itself.
  1182.         frameInfo->InitFromStorage(ev, storageUnitView);
  1183.     CATCH_ALL
  1184.         // Clean up the allocated memory.
  1185.         ODDeleteObject(frameInfo);
  1186.         // Alert the caller.
  1187.         RERAISE;
  1188.     ENDTRY
  1189.     
  1190.     return (ODInfoType)frameInfo;
  1191. }
  1192.  
  1193. //------------------------------------------------------------------------------
  1194. // Method:        WritePartInfo
  1195. // Origin:        ODPart
  1196. //
  1197. // Description:    When a frame is being externalized by the Draft, it will ask the
  1198. //                owner (part) to write out its info annotation on the frame.
  1199. //
  1200. //                The part uses a C++ helper class to encapsulate the information
  1201. //                we store with each frame, so we let it externalize itself to
  1202. //                the storage unit view.
  1203. //------------------------------------------------------------------------------
  1204.  
  1205. void SamplePart::WritePartInfo( Environment*        ev,
  1206.                                   ODInfoType            partInfo,
  1207.                                 ODStorageUnitView*    storageUnitView )
  1208. {
  1209.     SOM_Trace("SamplePart","WritePartInfo");
  1210.     
  1211.     // Tell our frame info class to write itself out into the pre-
  1212.     // focused storage unit.
  1213.     ((CFrameInfo*) partInfo)->Externalize(ev, storageUnitView);
  1214. }
  1215.  
  1216. //------------------------------------------------------------------------------
  1217. // Method:        ClonePartInfo
  1218. // Origin:        ODPart
  1219. //
  1220. // Description:    When a frame is being cloned by the Draft, it will ask the owner
  1221. //                (part) to clone its info annotation on the frame.
  1222. //
  1223. //                The part uses a C++ helper class to encapsulate the information
  1224. //                we store with each frame, so we let it clone itself to the
  1225. //                storage unit view.
  1226. //------------------------------------------------------------------------------
  1227.  
  1228. void SamplePart::ClonePartInfo( Environment*        ev,
  1229.                                 ODDraftKey            key,
  1230.                                   ODInfoType            partInfo,
  1231.                                 ODStorageUnitView*    storageUnitView,
  1232.                                 ODFrame*            scopeFrame )
  1233. {
  1234.     SOM_Trace("SamplePart","ClonePartInfo");
  1235.     
  1236.     // Tell our frame info class to write itself out into the pre-
  1237.     // focused storage unit.
  1238.     ((CFrameInfo*) partInfo)->CloneInto(ev, key, storageUnitView, scopeFrame);
  1239. }
  1240.  
  1241. //==============================================================================
  1242. #pragma mark    • Layout •
  1243. //==============================================================================
  1244.  
  1245. //------------------------------------------------------------------------------
  1246. // Method:        DisplayFrameAdded
  1247. // Origin:        ODPart
  1248. //
  1249. // Description:    This method is called in response to a frame being created for
  1250. //                the part.
  1251. //
  1252. //                The part records the existence of a new display frame in its
  1253. //                internal display frame list, as well as, verifies that the frame
  1254. //                is "set up" correctly (ie. valid viewType). The part also
  1255. //                creates and stores its "frame info" class in the new frame. 
  1256. //------------------------------------------------------------------------------
  1257.  
  1258. void SamplePart::DisplayFrameAdded( Environment*    ev,
  1259.                                        ODFrame*        frame )
  1260. {
  1261.     SOM_Trace("SamplePart","DisplayFrameAdded");
  1262.  
  1263.     // If we are being embedded in another part, the presentation field
  1264.     // will (most likely) be unset; we need to set it something meaningful.
  1265.     // The view field may also be unset, if so, we prefer to be displayed
  1266.     // in a frame view.
  1267.  
  1268.     if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation )
  1269.         frame->SetPresentation(ev, gGlobals->fMainPresentation);
  1270.     
  1271.     if ( frame->GetViewType(ev) == kODNullTypeToken )
  1272.         frame->SetViewType(ev, gGlobals->fFrameView);
  1273.         
  1274.     // Hang our "state" info off of the new display frame. We use
  1275.     // the CFrameInfo object for activation, updating, and window
  1276.     // maintenance.
  1277.     CFrameInfo* frameInfo = new CFrameInfo(ODGetSession(ev,fSelf));
  1278.     frame->SetPartInfo(ev, (ODInfoType)frameInfo);
  1279.     
  1280.     // If the frame being added is a root frame, we know that a window
  1281.     // is associated with this frame. Notify ourselves that we need to 
  1282.     // clean it up when the frame goes away.
  1283.     if ( frame->IsRoot(ev) )
  1284.         frameInfo->SetShouldDisposeWindow(kODTrue);
  1285.     
  1286.     // The proxy class will refcount the frame passed to it, so we
  1287.     // don't need to worry about refcounting the display frame.
  1288.     CFrameProxy* proxy = new CFrameProxy;
  1289.     proxy->InitFrameProxy(ev,frame);
  1290.  
  1291.     // Add the proxy to the display frame collection.
  1292.     fDisplayFrames->Add(proxy);
  1293.  
  1294.     // Since we maintain a persistent list of weak references to our
  1295.     // display frames, having one added to the part dirties it, but
  1296.     // only if the frame is "persistent".
  1297.     if ( frame->GetStorageUnit(ev) )
  1298.         this->SetDirty(ev);
  1299. }
  1300.  
  1301. //------------------------------------------------------------------------------
  1302. // Method:        DisplayFrameConnected
  1303. // Origin:        ODPart
  1304. //
  1305. // Description:    This method is called when one of our display frames, previously
  1306. //                written out, is internalized. This method is called instead of
  1307. //                DisplayFrameAdded because a "new" frame is not being created;
  1308. //                an existing one is being reconstituted.
  1309. //
  1310. //                The part first checks to see if we can match its frame to an
  1311. //                ID in the Display frame list; if so, we put the frame into the
  1312. //                proxy. For frames we do not recognize, just add them.
  1313. //
  1314. // Warning:        This method may be calle,d during editor swapping, with a frame
  1315. //                not recognized by the part. This is ok. Just treat the case as
  1316. //                if a "new" frame were being added to the part.
  1317. //------------------------------------------------------------------------------
  1318.  
  1319. void SamplePart::DisplayFrameConnected( Environment*    ev,
  1320.                                         ODFrame*        frame )
  1321. {
  1322.     SOM_Trace("SamplePart","DisplayFrameConnected");
  1323.  
  1324.     // Iterate over our display collection to match the frame with
  1325.     // an existing proxy with the correct frame ID. If we find it,
  1326.     // replace the ID with the actual frame. If we don't find it,
  1327.     // treat it as a newly "added" frame.
  1328.     ODBoolean found = kODFalse;
  1329.     CListIterator fiter(fDisplayFrames);
  1330.     for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1331.             fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1332.     {
  1333.         if ( proxy->GetID() == frame->GetID(ev) )
  1334.         {
  1335.             // The proxy class will refcount the frame passed to it, so we
  1336.             // don't need to worry about refcounting the display frame.
  1337.             proxy->SetFrame(ev,frame);
  1338.             found = kODTrue;
  1339.         }
  1340.     }
  1341.  
  1342.     // Parts typically operate under the assumption that they have previous
  1343.     // knowledge of a frame before it is connected to it. This knowledge
  1344.     // should come from having read in the frame reference when the part
  1345.     // was internalized. If the frame is an "unknown", the part was probably
  1346.     // bound to another editors storage unit because the editor is missing or
  1347.     // the user changed the editor in the Info dialog. 
  1348.     if ( found )
  1349.     {
  1350.         // If a display frame is connected to us with an unrecognizable
  1351.         // presentation, we need to set it to something meaningful.
  1352.     
  1353.         if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation )
  1354.             frame->SetPresentation(ev, gGlobals->fMainPresentation);
  1355.         
  1356.         if ( frame->IsRoot(ev) )
  1357.         {
  1358.             // If the frame being added is a root frame, we know that a window
  1359.             // is associated with this frame. Notify ourselves that we need to 
  1360.             // clean it up when the frame goes away.
  1361.             CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1362.             frameInfo->SetShouldDisposeWindow(kODTrue);
  1363.             
  1364.             // In addition, we need to verify that the frame is in "frame" view.
  1365.             // If the user dragged an icon from a document to Finder and then
  1366.             // opens the resultant document, the view would be "icon". However
  1367.             // displaying a icon is useless, so we need to change the view to
  1368.             // frame.
  1369.             if ( frame->GetViewType(ev) != gGlobals->fFrameView )
  1370.                 frame->SetViewType(ev, gGlobals->fFrameView);    
  1371.         }
  1372.     }
  1373.     else
  1374.     {
  1375.         // If an unrecognizable frame is connected to us, treat it like a "new"
  1376.         // frame and call our method to add it.
  1377.         this->DisplayFrameAdded(ev, frame);
  1378.     }
  1379. }
  1380.  
  1381. //------------------------------------------------------------------------------
  1382. // Method:        DisplayFrameRemoved
  1383. // Origin:        ODPart
  1384. //
  1385. // Description:    This method is called in response to a frame being removed from
  1386. //                the part.
  1387. //
  1388. //                The part removes the frame from its internal display frame list
  1389. //                and reliquishes any foci that it still owned. Lastly, if the
  1390. //                frame has a source frame (it was the root frame of a part
  1391. //                window), we will record the part window bounds so that any
  1392. //                subsequent part windows opened on the source frame will appear
  1393. //                in the same location.
  1394. //------------------------------------------------------------------------------
  1395.  
  1396. void SamplePart::DisplayFrameRemoved( Environment*    ev,
  1397.                                       ODFrame*        frame )
  1398. {
  1399.     SOM_Trace("SamplePart","DisplayFrameRemoved");
  1400.  
  1401.     TRY
  1402.         CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1403.     
  1404.         // Make sure the frame going away does not own any foci. Forgetting
  1405.         // to do this, will cause a "refcounting" error when the frame
  1406.         // is deleted by the draft.
  1407.         this->RelinquishAllFoci(ev, frame);
  1408.  
  1409.         // If removing a child window, show zoom rects back to source.
  1410.         // NOTE: This has to be done before CleanupDisplayFrame because 
  1411.         // CleanupDisplayFrame will remove the relationship.
  1412.         if ( frame->IsRoot(ev) && frameInfo->HasSourceFrame() )
  1413.         {
  1414.             TempODWindow window = frame->AcquireWindow(ev);
  1415.             this->ZoomPartWindow(ev, frameInfo->GetSourceFrame(ev),
  1416.                                     window, kWindowClosing);
  1417.         }
  1418.                 
  1419.         // Clean up the display frame.
  1420.         this->CleanupDisplayFrame(ev, frame, kFrameRemoved);
  1421.         // Clean up any associated window.
  1422.         this->CleanupWindow(ev, frame);
  1423.         // Dispose of the frame's runtime state info.
  1424.         frame->SetPartInfo(ev, (ODInfoType) kODNULL);
  1425.         ODDeleteObject(frameInfo);
  1426.         
  1427.         // Remove the display frame from our collection.
  1428.         CListIterator fiter(fDisplayFrames);
  1429.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1430.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1431.         {
  1432.             if ( ODObjectsAreEqual(ev, proxy->GetFrame(ev), frame) )
  1433.             {
  1434.                 // Delete the proxy object and its contents. The frame's
  1435.                 // refcount will be decremented in the proxy destructor.
  1436.                 fiter.RemoveCurrent();
  1437.                 delete proxy;
  1438.             }
  1439.         }
  1440.  
  1441.         // Since we maintain a persistent list of weak references to our
  1442.         // display frames, having one removed from the part dirties it, but
  1443.         // only if the frame is persistent.
  1444.         if ( frame->GetStorageUnit(ev) )
  1445.             this->SetDirty(ev);
  1446.     
  1447.     CATCH_ALL
  1448.         // Alert the user of the problem.
  1449.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
  1450.         // Change the exception value, so the DocShell doesn't display an
  1451.         // error dialog.
  1452.         SetErrorCode(kODErrAlreadyNotified);
  1453.         // Alert the caller.
  1454.         RERAISE;
  1455.     ENDTRY
  1456. }
  1457.  
  1458. //------------------------------------------------------------------------------
  1459. // Method:        DisplayFrameClosed
  1460. // Origin:        ODPart
  1461. //
  1462. // Description:    This method is called in response to a frame being closed as a
  1463. //                result of the document having been closed by the user.
  1464. //
  1465. //                The part behaves much the same way that it would if a frame were
  1466. //                removed (see above), except that we don't need to cache runtime
  1467. //                information. 
  1468. //------------------------------------------------------------------------------
  1469.  
  1470. void SamplePart::DisplayFrameClosed( Environment*    ev,
  1471.                                      ODFrame*        frame )
  1472. {
  1473.     SOM_Trace("SamplePart","DisplayFrameClosed");
  1474.  
  1475.     TRY
  1476.         CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1477.     
  1478.         // Make sure the frame going away does not own any foci. Forgetting
  1479.         // to do this, will cause a "refcounting" error when the frame
  1480.         // is deleted by the draft.
  1481.         this->RelinquishAllFoci(ev, frame);
  1482.  
  1483.         // Clean up the display frame.
  1484.         this->CleanupDisplayFrame(ev, frame, kFrameClosed);
  1485.         // Clean up any associated window.
  1486.         this->CleanupWindow(ev, frame);
  1487.         // Dispose of the frame's runtime state info.
  1488.         frame->SetPartInfo(ev, (ODInfoType) kODNULL);
  1489.         ODDeleteObject(frameInfo);
  1490.         
  1491.         // Remove the display frame from our collection.
  1492.         CListIterator fiter(fDisplayFrames);
  1493.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  1494.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  1495.         {
  1496.             if ( proxy->GetID() == frame->GetID(ev) )
  1497.             {
  1498.                 // Release the frame reference, but don't get rid of the
  1499.                 // proxy object because "closed" frames may be reconnected
  1500.                 // before the document is really closed.
  1501.                 proxy->Purge(ev);
  1502.             }
  1503.         }
  1504.         
  1505.     CATCH_ALL
  1506.         // Alert the user of the problem.
  1507.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame);
  1508.         // Change the exception value, so the DocShell doesn't display an
  1509.         // error dialog.
  1510.         SetErrorCode(kODErrAlreadyNotified);
  1511.         // Alert the caller.
  1512.         RERAISE;
  1513.     ENDTRY
  1514. }
  1515.  
  1516. //------------------------------------------------------------------------------
  1517. // Method:        CleanupDisplayFrame
  1518. // Origin:        SamplePart
  1519. //
  1520. // Description:    This method is called when a frame has been closed or removed.
  1521. //                The method cleans up the references and state information stored
  1522. //                in the CFrameInfo class.
  1523. //------------------------------------------------------------------------------
  1524.  
  1525. void SamplePart::CleanupDisplayFrame( Environment*    ev,
  1526.                                       ODFrame*        frame,
  1527.                                       ODBoolean        frameRemoved )
  1528. {
  1529.     SOM_Trace("SamplePart","CleanupDisplayFrame");
  1530.  
  1531.     ODError        error = noErr;
  1532.     CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1533.  
  1534.     TRY
  1535.         // If we are the root of a child window, we need to notify
  1536.         // our source frame that we are going away.
  1537.         if ( frameInfo->HasSourceFrame() )
  1538.         {
  1539.             ODFrame* sourceFrame = frameInfo->GetSourceFrame(ev);
  1540.             CFrameInfo* sourceFrameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev);
  1541.  
  1542.             if ( frameRemoved )
  1543.             {
  1544.                 // Invalidate the source frame. We do this because the
  1545.                 // source frame may have a unique display when it has
  1546.                 // been opened into a part window. This forces the
  1547.                 // frame to redraw "not opened".
  1548.                 sourceFrame->Invalidate(ev, kODNULL, kODNULL);
  1549.             }
  1550.             
  1551.             // Tell the source frame that its dependent is going away.
  1552.             sourceFrameInfo->ReleaseDependentFrame(ev);            
  1553.  
  1554.             // Release our reference to the source frame.
  1555.             frameInfo->ReleaseSourceFrame(ev);
  1556.  
  1557.             // If the frame is the root, it is a part window going away
  1558.             // and we need to notify our source frame that it no longer
  1559.             // has a part window.
  1560.             if ( frame->IsRoot(ev) )
  1561.                 sourceFrameInfo->SetPartWindow(ev, kODNULL);
  1562.         }
  1563.     CATCH_ALL
  1564.         error = ErrorCode();
  1565.     ENDTRY
  1566.     
  1567.     TRY
  1568.         // If the frame was removed from the document, we need to remove
  1569.         // any child window displaying that frame.
  1570.         if ( frameRemoved )
  1571.         {
  1572.             // If we have a child window, we need to close it.
  1573.             ODWindow* window = frameInfo->AcquirePartWindow(ev);
  1574.  
  1575.             if ( window )
  1576.             {
  1577.                 frameInfo->SetPartWindow(ev, kODNULL);
  1578.                 window->CloseAndRemove(ev);
  1579.             }
  1580.         }
  1581.     CATCH_ALL
  1582.         error = ErrorCode();
  1583.     ENDTRY
  1584.  
  1585.     TRY
  1586.         // If we have dependent frames, we need to notify them that we
  1587.         // are going away.
  1588.     
  1589.         if ( frameInfo->HasDependentFrame() )
  1590.         {
  1591.             // Get the frame that is dependent on this one. We can safely
  1592.             // do this because we only reference our own display frames.
  1593.             ODFrame* dependentFrame = frameInfo->GetDependentFrame(ev);
  1594.             CFrameInfo* dependentFrameInfo = (CFrameInfo*) dependentFrame->GetPartInfo(ev);
  1595.  
  1596.             // Tell the dependent frame that its source is going away.
  1597.             dependentFrameInfo->ReleaseSourceFrame(ev);
  1598.             
  1599.             // Release our reference to the dependent frame.
  1600.             frameInfo->ReleaseDependentFrame(ev);
  1601.         }
  1602.     CATCH_ALL
  1603.         error = ErrorCode();
  1604.     ENDTRY
  1605.     
  1606.     // If anything went wrong, signal an error.
  1607.     THROW_IF_ERROR(error);
  1608. }
  1609.  
  1610. //------------------------------------------------------------------------------
  1611. // Method:        AttachSourceFrame
  1612. // Origin:        ODPart
  1613. //
  1614. // Description:    If the part which we are contained in is opened into a part
  1615. //                window, it is required to iterate over its embedded frames and
  1616. //                add new display frames in the part window. After each new
  1617. //                embedded frame is created, this method will be called.
  1618. //
  1619. //                Given all that, and given our lack of interesting
  1620. //                content, we just validate the frame and attach it to its source.
  1621. //------------------------------------------------------------------------------
  1622.  
  1623. void SamplePart::AttachSourceFrame( Environment*    ev,
  1624.                                     ODFrame*        frame,
  1625.                                     ODFrame*        sourceFrame )
  1626. {
  1627.     SOM_Trace("SamplePart","AttachSourceFrame");
  1628.  
  1629.     // Tell the new frame about its source.
  1630.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1631.     frameInfo->SetSourceFrame(ev, sourceFrame);
  1632.     
  1633.     // And tell the source about its new dependent.
  1634.     frameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev);
  1635.     frameInfo->SetDependentFrame(ev, frame);
  1636.     
  1637.     // In both cases, refcounting of the frame and sourceFrame is
  1638.     // handled by the CFrameInfo class.
  1639. }
  1640.  
  1641. //------------------------------------------------------------------------------
  1642. // Method:        ViewTypeChanged
  1643. // Origin:        ODPart
  1644. //
  1645. // Description:    This method is called in response to one of our display frame's
  1646. //                viewType field being modified. We call this method on ourselves
  1647. //                when new display frames are added, but it call also be called
  1648. //                when the user changes the view in the "part info" dialog.
  1649. //------------------------------------------------------------------------------
  1650.  
  1651. void SamplePart::ViewTypeChanged( Environment*    ev,
  1652.                                   ODFrame*        frame )
  1653. {
  1654.     SOM_Trace("SamplePart","ViewTypeChanged");
  1655.  
  1656.     // Change this frame's used shape to match the new view setting.
  1657.     TempODShape newUsedShape = this->CalcNewUsedShape(ev, frame);    
  1658.  
  1659.     frame->Invalidate(ev, kODNULL, kODNULL);
  1660.     frame->ChangeUsedShape(ev, newUsedShape, kODNULL);
  1661.     frame->Invalidate(ev, kODNULL, kODNULL);
  1662. }
  1663.  
  1664. //------------------------------------------------------------------------------
  1665. // Method:        CalcNewUsedShape
  1666. // Origin:        SamplePart
  1667. //
  1668. // Description:    This method is called in response to one of display frame's view
  1669. //                being changed. The method calculates the appropriate usedShape
  1670. //                for the new view type.
  1671. //------------------------------------------------------------------------------
  1672.  
  1673. ODShape* SamplePart::CalcNewUsedShape( Environment*    ev,
  1674.                                          ODFrame*        frame )
  1675. {
  1676.     SOM_Trace("SamplePart","CalcNewUsedShape");
  1677.  
  1678.     ODShape* usedShape = kODNULL;        ODVolatile(usedShape);
  1679.     RgnHandle usedRgn;                    ODVolatile(usedRgn);
  1680.     
  1681.     // If the view is "frame", we intentionally return a nil shape;
  1682.     // doing so, will reset the used shape to equal the frame shape.
  1683.  
  1684.     ODTypeToken view = frame->GetViewType(ev);
  1685.  
  1686.     if ( view == gGlobals->fLargeIconView ||
  1687.             view == gGlobals->fSmallIconView ||
  1688.             view == gGlobals->fThumbnailView )
  1689.     {
  1690.         TRY
  1691.             Rect bounds;
  1692.             usedRgn = ODNewRgn();
  1693.  
  1694.             if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView )
  1695.             {
  1696.                 CUsingLibraryResources res;
  1697.  
  1698.                 // Set the bounds rect for the icon size.
  1699.                 SetRect(&bounds, 0, 0,
  1700.                         (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize,
  1701.                         (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize);
  1702.  
  1703.                 // Convert the icon mask into a Region.
  1704.                 THROW_IF_ERROR( IconIDToRgn(usedRgn, &bounds, atAbsoluteCenter, kBaseResourceID) );
  1705.             }
  1706.             else if ( view == gGlobals->fThumbnailView )
  1707.             {    
  1708.                 PicHandle thumbnail = this->GenerateThumbnail(ev, frame);
  1709.  
  1710.                 if ( thumbnail )
  1711.                     bounds = (**thumbnail).picFrame;
  1712.                 else
  1713.                     SetRect(&bounds, 0, 0, kODThumbnailSize, kODThumbnailSize);
  1714.                     
  1715.                 RectRgn(usedRgn,&bounds);
  1716.             }
  1717.         
  1718.             usedShape = frame->CreateShape(ev);
  1719.             usedShape->SetQDRegion(ev, usedRgn);
  1720.                             
  1721.         CATCH_ALL
  1722.             ODSafeReleaseObject(usedShape);
  1723.             ODDisposeHandle((ODHandle)usedRgn);
  1724.             usedShape = kODNULL;
  1725.         ENDTRY
  1726.     }
  1727.         
  1728.     return usedShape;
  1729. }
  1730.  
  1731. //------------------------------------------------------------------------------
  1732. // Method:        UpdateFrame
  1733. // Origin:        SamplePart
  1734. //
  1735. // Description:    This method is called in response to one of our
  1736. //------------------------------------------------------------------------------
  1737.  
  1738. void SamplePart::UpdateFrame( Environment*    ev,
  1739.                               ODFrame*        frame,
  1740.                               ODTypeToken    view,
  1741.                               ODShape*        usedShape )
  1742. {
  1743.     SOM_Trace("SamplePart","UpdateFrame");
  1744.  
  1745.     TRY
  1746.         // Update the frame to have the new view and UsedShape.
  1747.         frame->Invalidate(ev, kODNULL, kODNULL);
  1748.         frame->SetViewType(ev, view);
  1749.         frame->ChangeUsedShape(ev, usedShape, kODNULL);
  1750.         frame->Invalidate(ev, kODNULL, kODNULL);
  1751.     CATCH_ALL
  1752.         // Failing isn't great, but we can live with it, so don't set ev.
  1753.     ENDTRY
  1754. }
  1755.  
  1756. //------------------------------------------------------------------------------
  1757. // Method:        FrameShapeChanged
  1758. // Origin:        ODPart
  1759. //
  1760. // Description:    This method is called in response to a frame's shape being
  1761. //                altered, either by the user or the part we are embedded in.
  1762. //
  1763. //                To keep all dependent frames in sync, we need to propogate the
  1764. //                new frame shape the frames dependent on the changed frame. This
  1765. //                is done by observing the display frames stored in the frame info
  1766. //                and calling RequestFrameShape for each.
  1767. //------------------------------------------------------------------------------
  1768.  
  1769. void SamplePart::FrameShapeChanged( Environment*    ev,
  1770.                                     ODFrame*        frame )
  1771. {
  1772.     SOM_Trace("SamplePart","FrameShapeChanged");
  1773.  
  1774.     // Adjust the "used" shape for the new frame shape.
  1775.     TempODShape usedShape = this->CalcNewUsedShape(ev, frame);
  1776.     frame->ChangeUsedShape(ev, usedShape, kODNULL);
  1777. }
  1778.  
  1779. //------------------------------------------------------------------------------
  1780. // Method:        Open
  1781. // Origin:        ODPart
  1782. //
  1783. // Description:    This method is called when OpenDoc, a containing part, or the
  1784. //                active editor would like to open a frame into a seperate window.
  1785. //                If a source frame is passed into this method, the editor is
  1786. //                being asked one of two things. If the frame is the root, we are
  1787. //                being asked to open an existing document. If the frame is not
  1788. //                the root, we are being asked to open a part window. If a source
  1789. //                frame is not specified, the editor is being asked to open a new
  1790. //                window.
  1791. //------------------------------------------------------------------------------
  1792.  
  1793. ODID SamplePart::Open( Environment*        ev,
  1794.                        ODFrame*            frame )
  1795. {
  1796.     SOM_Trace("SamplePart","Open");
  1797.  
  1798.     ODID windowID;
  1799.     TempODWindow window(kODNULL);
  1800.  
  1801.     WindowProperties* windowProperties = kODNULL;
  1802.     ODVolatile(windowProperties);
  1803.  
  1804.     TRY
  1805.         // Because the frame parameter being passed to us can be one of
  1806.         // three things, we must determine what it is; either the root
  1807.         // frame of a existing document, the source frame for a part
  1808.         // window, or null if we are opening a new document.
  1809.     
  1810.         if ( frame == kODNULL )
  1811.         {
  1812.             // Calculate the bounding rectangle for a new window
  1813.             Rect windowRect = this->CalcPartWindowSize(ev, kODNULL);
  1814.             // Get the default setting for a document window.
  1815.             windowProperties = this->GetDefaultWindowProperties(ev, kODNULL, &windowRect);
  1816.             // Create a Mac Window and register it with OpenDoc.
  1817.             window = this->CreateWindow(ev, kODNULL, kODFrameObject, windowProperties);
  1818.         }
  1819.         else if ( frame->IsRoot(ev) )
  1820.         {
  1821.             // Get the previously saved settings for the document window.
  1822.             windowProperties = this->GetSavedWindowProperties(ev, frame);
  1823.             
  1824.             if ( windowProperties == kODNULL )
  1825.             {
  1826.                 // Calculate the bounding rectangle for a new window
  1827.                 Rect windowRect = this->CalcPartWindowSize(ev, frame);
  1828.                 // Get the default setting for a document window.
  1829.                 windowProperties = this->GetDefaultWindowProperties(ev, kODNULL, &windowRect);
  1830.             }
  1831.  
  1832.             // Create a Mac Window and register it with OpenDoc.
  1833.             window = this->CreateWindow(ev, frame, kODFrameObject, windowProperties);
  1834.             
  1835.             // We release the source frame here because we didn't call
  1836.             // EndGetWindowProperties and becuase we are done with it.
  1837.             ODReleaseObject(ev, windowProperties->sourceFrame);
  1838.         }
  1839.         else // frame is a source frame
  1840.         {
  1841.             window = this->AcquireFramesWindow(ev, frame);
  1842.     
  1843.             if ( window == kODNULL )
  1844.             {
  1845.                 // Calculate the bounding rectangle for a new window
  1846.                 Rect windowRect = this->CalcPartWindowSize(ev, frame);
  1847.                 // Get the default setting for a document window.
  1848.                 windowProperties = this->GetDefaultWindowProperties(ev, frame, &windowRect);
  1849.                 // Create a Mac Window and register it with OpenDoc.
  1850.                 window = this->CreateWindow(ev, kODNULL, kODFrameObject, windowProperties);
  1851.                 
  1852.                 // Tell the source frame that it is opened in a part window.
  1853.                 CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1854.                 frameInfo->SetPartWindow(ev, window);
  1855.     
  1856.                 this->ZoomPartWindow(ev, frame, window, kWindowOpening);
  1857.             }
  1858.         }
  1859.     
  1860.         // Create the window's root facet.
  1861.         window->Open(ev);
  1862.         // Make the window visible.
  1863.         window->Show(ev);
  1864.         // Activate and select the window.
  1865.         window->Select(ev);
  1866.     
  1867.         // Cleanup allocate memory.
  1868.         ODDeleteObject(windowProperties);
  1869.         
  1870.         // Get window id to return.
  1871.         windowID = (window ? window->GetID(ev) : kODNULLID);
  1872.     
  1873.     CATCH_ALL
  1874.         // If we threw early, the source frame's refcount may be too high.
  1875.         if ( windowProperties )
  1876.             ODSafeReleaseObject(windowProperties->sourceFrame);
  1877.         // Cleanup the created items.
  1878.         ODDeleteObject(windowProperties);
  1879.         windowID = kODNULLID;
  1880.         // Alert the caller.
  1881.         RERAISE;
  1882.     ENDTRY
  1883.  
  1884.     return windowID;
  1885. }
  1886.  
  1887. //------------------------------------------------------------------------------
  1888. // Method:        AcquireFramesWindow
  1889. // Origin:        SamplePart
  1890. //
  1891. // Description:    This method is called by the part when a frame, that has been
  1892. //                previously opened, is being opened again.
  1893. //
  1894. //                The method retrieves the existing window for the frame and
  1895. //                returns it.                
  1896. //------------------------------------------------------------------------------
  1897.  
  1898. ODWindow* SamplePart::AcquireFramesWindow(    Environment*    ev,
  1899.                                                ODFrame*        frame )
  1900. {
  1901.     SOM_Trace("SamplePart","GetFramesWindow");
  1902.  
  1903.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  1904.     ODWindow* window = frameInfo->AcquirePartWindow(ev);
  1905.  
  1906.     return window;
  1907. }
  1908.     
  1909. //------------------------------------------------------------------------------
  1910. // Method:        CreateWindow
  1911. // Origin:        SamplePart
  1912. //
  1913. // Description:    This method is called by the part when a window needs to be
  1914. //                created for a frame being opened.
  1915. //
  1916. //                The part uses the information passed in windowProperties to 
  1917. //                create the appropriate window. The generated window is
  1918. //                registered with OpenDoc as a new window (RegisterWindow) or as a
  1919. //                window from an existing document (RegisterWindowForFrame).
  1920. //------------------------------------------------------------------------------
  1921.  
  1922. ODWindow* SamplePart::CreateWindow( Environment*         ev,
  1923.                                     ODFrame*            frame,
  1924.                                     ODType                frameType,
  1925.                                     WindowProperties*    windowProperties)
  1926. {
  1927.     SOM_Trace("SamplePart","CreateWindow");
  1928.  
  1929.     ODPlatformWindow    platformWindow    = kODNULL;
  1930.     ODWindow*            window            = kODNULL;
  1931.     
  1932.     // Using the name and the calculated rectangle, create a new window.
  1933.     // Note that we are allocating the window record in temp mem using
  1934.     // the OpenDoc memory mgr. This helps reduce app heap usage.
  1935.     // In addition, OpenDoc requires that all new windows be initially hidden
  1936.     // so that it can correctly layer windows/palettes.
  1937.     platformWindow = NewCWindow((Ptr)ODNewPtr(sizeof(WindowRecord)),
  1938.                                 &(windowProperties->boundsRect),
  1939.                                 windowProperties->title,
  1940.                                 kODFalse, /* visible */
  1941.                                 windowProperties->procID,
  1942.                                 (WindowPtr)-1L,
  1943.                                 windowProperties->hasCloseBox,
  1944.                                 windowProperties->refCon);
  1945.  
  1946.     if ( platformWindow )
  1947.     {
  1948.         TRY
  1949.             ODWindowState* windowState = ODGetSession(ev,fSelf)->GetWindowState(ev);
  1950.             
  1951.             // Shoud the window be saved in the document? Yes if the root frame is
  1952.             // persistent.
  1953.             ODBoolean saveWindow = (ODISOStrCompare(frameType,kODFrameObject) == 0);
  1954.             
  1955.             // Tell the window object that we will be disposing the window record
  1956.             // when the root frame is closed/removed.
  1957.             ODBoolean shouldDispose = kODFalse;
  1958.                                 
  1959.             // Determine whether we are creating a new window (frame is null),
  1960.             // or opening a previous saved window (frame is valid).
  1961.             
  1962.             if ( frame == kODNULL )
  1963.             {                                
  1964.                 // Tell OpenDoc about it by creating an OpenDoc window object.
  1965.                 window = windowState->
  1966.                             RegisterWindow(ev, 
  1967.                                 platformWindow,                    // Macintosh WindowPtr
  1968.                                 frameType,                        // Frame type (Persistent/Non-persistent)
  1969.                                 windowProperties->isRootWindow,    // Is this a document window?
  1970.                                 windowProperties->isResizable,    // Is this window resizeable?
  1971.                                 windowProperties->isFloating,    // Is this window floating?
  1972.                                 saveWindow,                        // Should this window be persistent?
  1973.                                 shouldDispose,                    // (see comment above)
  1974.                                 fSelf,                            // Part reference to us
  1975.                                 gGlobals->fFrameView,            // What view should the window have?
  1976.                                 gGlobals->fMainPresentation,    // What presentation should the window have?
  1977.                                 windowProperties->sourceFrame);    // The display frame being opened, if any
  1978.             }
  1979.             else
  1980.             {
  1981.                 // Tell OpenDoc about it by creating an OpenDoc window object.
  1982.                 window = windowState->
  1983.                             RegisterWindowForFrame(ev, 
  1984.                                 platformWindow,                    // Macintosh WindowPtr
  1985.                                 frame,                             // Frame type (Persistent/Non-persistent)
  1986.                                 windowProperties->isRootWindow,    // Is this a document window?
  1987.                                 windowProperties->isResizable,    // Is this window resizeable?
  1988.                                 windowProperties->isFloating,    // Is this window floating?
  1989.                                 saveWindow,                        // Should this window be persistent?
  1990.                                 shouldDispose,                    // (see comment above)
  1991.                                 windowProperties->sourceFrame);    // The display frame being opened, if any
  1992.             }
  1993.             
  1994.         CATCH_ALL
  1995.             // Cleanup Macintosh Window.
  1996.             CloseWindow(platformWindow);
  1997.             ODDisposePtr(platformWindow);
  1998.             // Get the right error message for the problem.
  1999.             ODSShort errMsgNum = (!frame && windowProperties->sourceFrame)
  2000.                                     ? kErrCantOpenPartWindow : kErrCantOpenDocWindow;
  2001.             // Alert the user of the problem.
  2002.             this->DoDialogBox(ev, frame, kErrorBoxID, errMsgNum);
  2003.             // Change the exception value, so the DocShell doesn't display an
  2004.             // error dialog.
  2005.             SetErrorCode(kODErrAlreadyNotified);
  2006.             // Alert the caller.
  2007.             RERAISE;
  2008.         ENDTRY
  2009.     }
  2010.  
  2011.     return window;
  2012. }
  2013.     
  2014. //------------------------------------------------------------------------------
  2015. // Method:        CleanupWindow
  2016. // Origin:        SamplePart
  2017. //
  2018. // Description:    This method is called by the part when a window needs to be
  2019. //                cleaned up for a frame being closed/removed.
  2020. //
  2021. //                The part deallocates the window buffer allocated in the
  2022. //                CreateWindow() method.
  2023. //------------------------------------------------------------------------------
  2024.  
  2025. void SamplePart::CleanupWindow( Environment*     ev,
  2026.                                 ODFrame*        frame )
  2027. {
  2028.     SOM_Trace("SamplePart","CleanupWindow");
  2029.     
  2030.        TRY
  2031.         CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2032.         if ( frameInfo->ShouldDisposeWindow() )
  2033.         {
  2034.             TempODWindow window = frame->AcquireWindow(ev);
  2035.             THROW_IF_NULL(window);
  2036.             
  2037.             ODPlatformWindow windowPtr = window->GetPlatformWindow(ev);
  2038.             CloseWindow(windowPtr);
  2039.             ODDisposePtr(windowPtr);
  2040.         }
  2041.     CATCH_ALL
  2042.         this->DoDialogBox(ev, frame, kErrorBoxID, kErrWindowGone);
  2043.         // consume excpetion because it's not fatal.
  2044.     ENDTRY
  2045. }
  2046.  
  2047. //------------------------------------------------------------------------------
  2048. // Method:        GetDefaultWindowProperties
  2049. // Origin:        SamplePart
  2050. //
  2051. // Description:    This method is called by the part when a new window is being
  2052. //                created. The method examines the frame which is being opened
  2053. //                a generates the default window parameters to pass to the
  2054. //                Mac Toolbox.
  2055. //------------------------------------------------------------------------------
  2056.  
  2057. WindowProperties*
  2058. SamplePart::GetDefaultWindowProperties( Environment*     ev,
  2059.                                         ODFrame*        sourceFrame,
  2060.                                         Rect*            windowRect )
  2061. {
  2062.     SOM_Trace("SamplePart","GetDefaultWindowProperties");
  2063.     
  2064.     WindowProperties* windowProperties = new WindowProperties;
  2065.  
  2066.     TRY
  2067.         // Calculate the offset for the window based on the sourceFrame.    
  2068.         if ( sourceFrame )
  2069.             this->CalcPartWindowPosition(ev, sourceFrame, windowRect);
  2070.         else
  2071.             OffsetRect(windowRect, kALittleNudge,
  2072.                         GetMBarHeight() + kMacWindowTitleBarHeight);    
  2073.     
  2074.         // Set the window bounds based on the calculated rect.
  2075.         windowProperties->boundsRect = *windowRect;
  2076.     
  2077.         // Get the part's name to use for the new window.
  2078.         TempODIText windowName = GetPartName(ev, fSelf, kSamplePartCategory);
  2079.         // Convert the ODIText into a Pascal string.
  2080.         GetITextString(windowName, windowProperties->title);
  2081.         
  2082.         // Fill in the other fields of the Window Properties struct.
  2083.         
  2084.         windowProperties->procID = zoomDocProc;
  2085.         windowProperties->hasCloseBox = kODTrue;
  2086.         windowProperties->refCon = (long) kODNULL;
  2087.         windowProperties->wasVisible = kODFalse;
  2088.         windowProperties->isResizable = kODTrue;
  2089.         windowProperties->isFloating = kODFalse;
  2090.         windowProperties->isRootWindow = sourceFrame ? kODFalse : kODTrue;
  2091.         windowProperties->shouldShowLinks = kODFalse;
  2092.         windowProperties->sourceFrame = sourceFrame;
  2093.     CATCH_ALL
  2094.         // Clean up and...
  2095.         ODDeleteObject(windowProperties);
  2096.         // Alert the caller.
  2097.         RERAISE;
  2098.     ENDTRY
  2099.     
  2100.     return windowProperties;
  2101. }
  2102.  
  2103. //------------------------------------------------------------------------------
  2104. // Method:        GetSavedWindowProperties
  2105. // Origin:        SamplePart
  2106. //
  2107. // Description:    This method is called by the part to read in saved information
  2108. //                for a window from an existing document.
  2109. //------------------------------------------------------------------------------
  2110.  
  2111. WindowProperties* SamplePart::GetSavedWindowProperties( Environment*     ev,
  2112.                                                           ODFrame*        frame )
  2113. {
  2114.     SOM_Trace("SamplePart","GetSavedWindowProperties");
  2115.  
  2116.     WindowProperties* windowProperties = new WindowProperties;
  2117.     
  2118.     // If we fail to load the window properties from storage, delete
  2119.     // the structure so the calling code will behave appropriately.    
  2120.     if ( BeginGetWindowProperties(ev, frame, windowProperties) )
  2121.     {    
  2122.         // Note: We don't call EndGetWindowProperties because it releases the
  2123.         // source frame, which we will need after this method returns.
  2124.         
  2125.         // Get the part's name to use for the new window.
  2126.         TempODIText windowName = GetPartName(ev, fSelf, kSamplePartCategory);
  2127.         // Convert the ODIText into a Pascal string.
  2128.         GetITextString(windowName, windowProperties->title);
  2129.     
  2130.         // Verify the window is still visible on a monitor.
  2131.         
  2132.         RgnHandle windowRgn = ODNewRgn();
  2133.         ODBoolean repositionWindow = kODFalse;
  2134.         
  2135.         // We are only concerned with the window's title bar being
  2136.         // visible, so calcuate the titlebar rect from the current
  2137.         // window bounds.
  2138.         Rect adjustedBounds = windowProperties->boundsRect;
  2139.         adjustedBounds.bottom = adjustedBounds.top;
  2140.         adjustedBounds.top -= kMacWindowTitleBarHeight;
  2141.         
  2142.         // Intersect the monitor's region
  2143.         RectRgn(windowRgn, &adjustedBounds);
  2144.         SectRgn(windowRgn, GetGrayRgn(), windowRgn);
  2145.         
  2146.         if ( !EmptyRgn(windowRgn) )
  2147.         {
  2148.             // If the visible portion of the window is too small, we need
  2149.             // to reposition it.
  2150.             Rect intersectedBounds = (**windowRgn).rgnBBox;
  2151.             if ( (intersectedBounds.right-intersectedBounds.left < kMinHorzVisPortion) ||
  2152.                     (intersectedBounds.bottom-intersectedBounds.top < kMinVertVisPortion) )
  2153.                 repositionWindow = kODTrue;
  2154.         }
  2155.         else
  2156.         {
  2157.             // If the window is completely offscreen, we need to reposition it.
  2158.             repositionWindow = kODTrue;
  2159.         }
  2160.         ODDisposeHandle((ODHandle)windowRgn);
  2161.         
  2162.         // If not, we need to move it so the user can see it.
  2163.         if ( repositionWindow )
  2164.         {
  2165.             Rect windowRect = (windowProperties->boundsRect);
  2166.             // Move the window to {0,0} coordinates.
  2167.             OffsetRect(&windowRect, -windowRect.left, -windowRect.top);
  2168.             // Now move the window to the default window position.
  2169.             OffsetRect(&windowRect, kALittleNudge, GetMBarHeight() + kMacWindowTitleBarHeight);
  2170.             // Save the new window position in our windowProperties.
  2171.             windowProperties->boundsRect = windowRect;
  2172.         }
  2173.     }
  2174.     else
  2175.     {
  2176.         // If we were unable to re-load window properties, dispose of the
  2177.         // struct.
  2178.         ODDeleteObject(windowProperties);
  2179.     }
  2180.         
  2181.     return windowProperties;
  2182. }
  2183.  
  2184. //------------------------------------------------------------------------------
  2185. // Method:        CalcPartWindowSize
  2186. // Origin:        SamplePart
  2187. //
  2188. // Description:    This method is called by the part to determine what size a new
  2189. //                window shoud be.
  2190. //------------------------------------------------------------------------------
  2191.  
  2192. Rect SamplePart::CalcPartWindowSize( Environment*    ev,
  2193.                                      ODFrame*        sourceFrame )
  2194. {
  2195.     SOM_Trace("SamplePart","CalcPartWindowSize");
  2196.  
  2197.     const ODSShort kOnePageWidth = 600;
  2198.     
  2199.     Rect    windowRect;
  2200.     ODRect    frameRect;
  2201.     
  2202.     // If a source frame is given, the part is being asked to open one of
  2203.     // its display frames into a part window. Otherwise, we are being opened
  2204.     // as the root frame of the current document and should size the window
  2205.     // accordingly.
  2206.  
  2207.     // Set up the child window's size to be that of the display frame being opened.
  2208.     if ( sourceFrame )
  2209.     {
  2210.         // Retrieve the fixed point bounding box for the frame.
  2211.         TempODShape frameShape = sourceFrame->AcquireFrameShape(ev, kODNULL);
  2212.         frameShape->GetBoundingBox(ev, &frameRect);
  2213.         
  2214.         // Convert that into a Quickdraw rectangle.
  2215.         FixedToIntRect(frameRect, windowRect);
  2216.     }
  2217.     // Otherwise, just open a large window.
  2218.     else
  2219.     {
  2220.         // (3 * kODLargeIconSize) prevents the window from covering the volume
  2221.         // icons on the desktop which is a violation of Macintosh HI Guidelines.
  2222.         
  2223.         SetRect(&windowRect, 0, 0,
  2224.                   ODQDGlobals.screenBits.bounds.right - (3 * kODLargeIconSize),
  2225.                   ODQDGlobals.screenBits.bounds.bottom
  2226.                       - GetMBarHeight() - kMacWindowTitleBarHeight - kALittleNudge);        
  2227.         
  2228.         if ( windowRect.right - windowRect.left > kOnePageWidth )
  2229.             windowRect.right = windowRect.left + kOnePageWidth;
  2230.     }
  2231.     
  2232.     return windowRect;
  2233. }
  2234.  
  2235. //------------------------------------------------------------------------------
  2236. // Method:        CalcPartWindowPosition
  2237. // Origin:        SamplePart
  2238. //
  2239. // Description:    This method is called by the part to determine where to align
  2240. //                the new window (top left corner of the screen or tiled to a
  2241. //                frame).
  2242. //------------------------------------------------------------------------------
  2243.  
  2244. Rect SamplePart::CalcPartWindowPosition( Environment*    ev,
  2245.                                          ODFrame*        frame,
  2246.                                          Rect*            partWindowBounds )
  2247. {
  2248.     SOM_Trace("SamplePart","CalcPartWindowPosition");
  2249.  
  2250.     ODFacet*        activeFacet;
  2251.     ODShape*        frameShape;
  2252.     ODRect            bbox;
  2253.     Rect            bounds;
  2254.     
  2255.     // We need to know which facet of the frame we are opening to position
  2256.     // the child window.
  2257.     activeFacet = this->GetActiveFacetForFrame(ev, frame);
  2258.     
  2259.     // This should never occur, but if it did, it would be fatal.
  2260.     // So we will just pass back the same rectangle.
  2261.     if ( activeFacet == kODNULL )
  2262.         return *partWindowBounds;
  2263.     
  2264.     // For the purposes of tiling, we need the to know the area of the
  2265.     // document the frame occupies. We do this by getting the bouding
  2266.     // box and offsetting it by the aggregate external window transform
  2267.     // of the facet.
  2268.     
  2269.     frameShape = activeFacet->GetFrame(ev)->AcquireFrameShape(ev, kODNULL);
  2270.     TempODTransform windowFrameTransform = activeFacet->AcquireWindowFrameTransform(ev, kODNULL);
  2271.     TempODShape boundsShape = ODCopyAndRelease(ev, frameShape);
  2272.  
  2273.     // Translate the bounds rect into window coordinates.
  2274.     boundsShape->Transform(ev, windowFrameTransform);
  2275.     
  2276.     // Get and convert the bounding box into a QuickDraw rectangle.
  2277.     boundsShape->GetBoundingBox(ev, &bbox);
  2278.     FixedToIntRect(bbox, bounds);
  2279.         
  2280.     // We then call our method to tile the child window.
  2281.     *partWindowBounds = TilePartWindow(ev, &bounds, partWindowBounds);
  2282.     
  2283.     // Set the port and origin so we can convert the rect to
  2284.     // global Window Mgr coordinates.
  2285.     SetPort(activeFacet->GetCanvas(ev)->GetQDPort(ev));
  2286.     SetOrigin(0,-kMacWindowTitleBarHeight);
  2287.     
  2288.     // Convert the local coordinates to global Window Mgr coordinates.
  2289.     LocalToGlobal((Point*)(&(partWindowBounds->top)));
  2290.     LocalToGlobal((Point*)(&(partWindowBounds->bottom)));
  2291.     
  2292.     return *partWindowBounds;
  2293. }
  2294.  
  2295. //------------------------------------------------------------------------------
  2296. // Method:        ZoomPartWindow
  2297. // Origin:        SamplePart
  2298. //
  2299. // Description:    This method is called by the part when a frame is being opened
  2300. //                or closed in the case that zooming rectangles should be shown.                
  2301. //------------------------------------------------------------------------------
  2302.  
  2303. void SamplePart::ZoomPartWindow( Environment*        ev,
  2304.                                     ODFrame*            frame,
  2305.                                     ODWindow*            window,
  2306.                                     ODBoolean            openingWindow )
  2307. {
  2308.     SOM_Trace("SamplePart","ZoomPartWindow");
  2309.  
  2310.     const ODSShort kNumZoomSteps = 12;
  2311.  
  2312.     Rect frameRect;
  2313.     {
  2314.         // We need to know which facet of the frame we are opening to position
  2315.         // the child window.
  2316.         ODFacet* zoomFacet = kODNULL;
  2317.         
  2318.         TRY
  2319.             zoomFacet = this->GetActiveFacetForFrame(ev, frame);
  2320.         CATCH_ALL
  2321.         ENDTRY
  2322.         
  2323.         // In case there isn't an active facet for the frame, .
  2324.         if ( zoomFacet == kODNULL )
  2325.         {
  2326.             TempODFrameFacetIterator iter(ev, frame);
  2327.             zoomFacet = iter.First();
  2328.         }
  2329.         
  2330.         if ( zoomFacet != kODNULL )
  2331.         {
  2332.             // For doing the zoom rects, we need the to know the area of the
  2333.             // document the frame occupies. We do this by getting the bouding
  2334.             // box and offsetting it by the aggregate external window transform
  2335.             // of the facet.
  2336.             TempODTransform windowFrameTransform =
  2337.                                 zoomFacet->AcquireWindowFrameTransform(ev, kODNULL);
  2338.             TempODShape boundsShape =
  2339.                                 ODCopyAndRelease(ev, zoomFacet->GetFrame(ev)
  2340.                                                     ->AcquireFrameShape(ev, kODNULL));
  2341.             
  2342.             // Translate the bounds rect into window coordinates.
  2343.             boundsShape->Transform(ev, windowFrameTransform);
  2344.             
  2345.             // Get and convert the bounding box into a QuickDraw rectangle.
  2346.             ODRect bbox;
  2347.             boundsShape->GetBoundingBox(ev, &bbox);
  2348.             FixedToIntRect(bbox, frameRect);
  2349.                 
  2350.             // Set the port and origin so we can convert the rect to
  2351.             // global Window Mgr coordinates.
  2352.             SetPort(zoomFacet->GetCanvas(ev)->GetQDPort(ev));
  2353.             SetOrigin(0, 0);
  2354.             
  2355.             // Convert the local coordinates to global Window Mgr coordinates.
  2356.             LocalToGlobal((Point*) &frameRect.top);
  2357.             LocalToGlobal((Point*) &frameRect.bottom);
  2358.         }
  2359.     }
  2360.     
  2361.     Rect windowRect;
  2362.     {
  2363.         ODPlatformWindow platformWindow = window->GetPlatformWindow(ev);
  2364.  
  2365.         windowRect = platformWindow->portRect;
  2366.         windowRect.top -= kMacWindowTitleBarHeight;
  2367.         
  2368.         // Set the port and origin so we can convert the rect to
  2369.         // global Window Mgr coordinates.
  2370.         SetPort(platformWindow);
  2371.         SetOrigin(0, 0);
  2372.         
  2373.         // Convert the local coordinates to global Window Mgr coordinates.
  2374.         LocalToGlobal((Point*) &windowRect.top);
  2375.         LocalToGlobal((Point*) &windowRect.bottom);
  2376.     }
  2377.     
  2378.     Rect fromRect = openingWindow ? frameRect  : windowRect;
  2379.     Rect toRect   = openingWindow ? windowRect : frameRect;
  2380.     
  2381.     if ( !openingWindow )
  2382.         window->Hide(ev);
  2383.  
  2384.     ZoomRects(&fromRect, &toRect, kNumZoomSteps, 
  2385.                 openingWindow ? zoomAccelerate : zoomDecelerate);
  2386. }
  2387.  
  2388. //------------------------------------------------------------------------------
  2389. // Method:        GetActiveFacetForFrame
  2390. // Origin:        SamplePart
  2391. //
  2392. // Description:    This method is called by the part when it needs to know what the
  2393. //                current active facet is.
  2394. //
  2395. //                The part uses this method specifically to find the facet of a
  2396. //                source frame when opening a part window.
  2397. //------------------------------------------------------------------------------
  2398.  
  2399. ODFacet* SamplePart::GetActiveFacetForFrame( Environment*    ev,
  2400.                                              ODFrame*        frame )
  2401. {
  2402.     SOM_Trace("SamplePart","GetActiveFacetForFrame");
  2403.  
  2404.     ODFacet*    facet = kODNULL;
  2405.     CFrameInfo*    frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2406.     
  2407.     // If the frame is active, and it should be, get the active facet
  2408.     // from the frame state info.
  2409.     if ( frameInfo->IsFrameActive() )
  2410.     {
  2411.         facet = frameInfo->GetActiveFacet();
  2412.     }
  2413.     else
  2414.     // Otherwise, iterate over the display frames looking for one
  2415.     // that has an active facet... there should be at least one.
  2416.     {
  2417.         TempODFrameFacetIterator fiter(ev, frame);
  2418.         for ( ODFacet* selectedFacet = fiter.First(); fiter.IsNotComplete();
  2419.               selectedFacet = fiter.Next() )
  2420.         {
  2421.             if ( selectedFacet->IsSelected(ev) )
  2422.             {
  2423.                 facet = selectedFacet;
  2424.                 break;
  2425.             }
  2426.         }
  2427.     }
  2428.     
  2429.     // If there are no active facets anywhere, this method should never
  2430.     // have been called, so signal an error.
  2431.     if ( facet == kODNULL )
  2432.         THROW(kODErrInvalidFrame);
  2433.         
  2434.     return facet;
  2435. }
  2436.  
  2437. //==============================================================================
  2438. #pragma mark    • Imaging •
  2439. //==============================================================================
  2440.  
  2441. //------------------------------------------------------------------------------
  2442. // Method:        FacetAdded
  2443. // Origin:        ODPart
  2444. //
  2445. // Description:    This method is called when any part adds a facet to
  2446. //                one of our display frames.
  2447. //------------------------------------------------------------------------------
  2448.  
  2449. void SamplePart::FacetAdded( Environment*    ev,
  2450.                              ODFacet*        facet )
  2451. {
  2452.     SOM_Trace("SamplePart","FacetAdded");
  2453.  
  2454.     ODFrame* frame = facet->GetFrame(ev);
  2455.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2456.         
  2457.     // If a root facet is being added, the frame should be activated when the
  2458.     // window is "selected". This prevents OpenDoc from getting into an
  2459.     // ambiguous state of no part having the selection focus.
  2460.  
  2461.     if ( frame->IsRoot(ev) )
  2462.     {
  2463.         frameInfo->SetActiveFacet(facet);
  2464.         frameInfo->SetFrameReactivate(kODTrue);
  2465.     }
  2466.     
  2467.     // If a frame had all of its facets removed, the frame would have
  2468.     // hidden any of its part windows. If the frame becomes visible again,
  2469.     // by having a facet added to it, we will "show" the part window for
  2470.     // the frame.
  2471.     
  2472.     if ( (CountFramesFacets(ev, frame) == 1) )
  2473.     {
  2474.         TempODWindow window = frameInfo->AcquirePartWindow(ev);
  2475.         if ( window ) window->Show(ev);
  2476.     }
  2477. }
  2478.  
  2479. //------------------------------------------------------------------------------
  2480. // Method:        FacetRemoved
  2481. // Origin:        ODPart
  2482. //
  2483. // Description:    This method is called when any part removes a facet
  2484. //                from one of our display frames.
  2485. //
  2486. //                The part just removes the "active" note from the
  2487. //                appropriate display frame if necessary since this
  2488. //                facet will not be available, nor active, again.
  2489. //------------------------------------------------------------------------------
  2490.  
  2491. void SamplePart::FacetRemoved( Environment*    ev,
  2492.                                ODFacet*        facet )
  2493. {
  2494.     SOM_Trace("SamplePart","FacetRemoved");
  2495.  
  2496.     ODFrame*    frame = facet->GetFrame(ev);
  2497.     TempODFrame    containingFrame = frame->AcquireContainingFrame(ev);
  2498.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  2499.  
  2500.     // If the facet was the active facet, it can no longer be.
  2501.        if ( ODObjectsAreEqual(ev, frameInfo->GetActiveFacet(), facet) )
  2502.         frameInfo->SetActiveFacet(kODNULL);
  2503.  
  2504.     // If a frame has all of its facets removed and its containing frame set
  2505.     // to NULL, the frame becomes "hidden". If the frame owns a part window,
  2506.     // the part window should also be hidden.
  2507.     
  2508.     if ( (CountFramesFacets(ev, frame) == 0) &&
  2509.             (containingFrame == kODNULL) )
  2510.     {
  2511.         TempODWindow window = frameInfo->AcquirePartWindow(ev);
  2512.         if ( window ) window->Hide(ev);
  2513.     }
  2514. }
  2515.  
  2516. //------------------------------------------------------------------------------
  2517. // Method:        Draw
  2518. // Origin:        ODPart
  2519. //
  2520. // Description:    This method is called when a facet of a part's display
  2521. //                frame intersects the invalidated portion of an OpenDoc
  2522. //                window. The invalidShape parameter passed in is the
  2523. //                portion of the facet which has been invalidated.
  2524. //
  2525. //                The part sets up the drawing environment using a
  2526. //                C++ helper class (CFocus) and then calls the
  2527. //                appropriate drawing method based on the frame's
  2528. //                viewType.
  2529. //------------------------------------------------------------------------------
  2530.  
  2531. void SamplePart::Draw( Environment*        ev,
  2532.                        ODFacet*            facet,
  2533.                        ODShape*            invalidShape )
  2534. {
  2535.     SOM_Trace("SamplePart","Draw");
  2536.  
  2537.     // Focus the port and origin for drawing in our facet.
  2538.     // Note that this instance of the CFocusDrawingEnv class
  2539.     // is being allocated on the stack. When the execution
  2540.     // leaves the scope of this method, the destructor (which
  2541.     // cleans up the drawing environment) is automatically
  2542.     // called.
  2543.     CFocus initiateDrawing(ev, facet, invalidShape);
  2544.     
  2545.     ODTypeToken view = facet->GetFrame(ev)->GetViewType(ev);
  2546.     
  2547.     if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView )
  2548.         this->DrawIconView(ev, facet);
  2549.     else if ( view == gGlobals->fThumbnailView )
  2550.         this->DrawThumbnailView(ev, facet);
  2551.     else
  2552.         this->DrawFrameView(ev, facet);
  2553. }
  2554.  
  2555. //------------------------------------------------------------------------------
  2556. // Method:        DrawFrameView
  2557. // Origin:        SamplePart
  2558. //
  2559. // Description:    This method is called by the part when the frame being drawn is
  2560. //                in "frame" view.
  2561. //
  2562. //                SamplePart really has not intrisic content. However, to provide
  2563. //                some visual display, we draw the class name at 80% of the
  2564. //                frame's current height using an bold font.
  2565. //------------------------------------------------------------------------------
  2566.  
  2567. void SamplePart::DrawFrameView( Environment*    ev,
  2568.                                 ODFacet*        facet )
  2569. {
  2570.     SOM_Trace("SamplePart","DrawFrameView");
  2571.  
  2572. /*ForTSMTE
  2573.     ODFrame*    frame;
  2574.     ODUShort    frameHeight = 0;
  2575.     ODUShort    frameWidth = 0;
  2576.     RgnHandle    frameRgn;
  2577.     FontInfo    finfo;
  2578.     Str63        defaultString;
  2579.     CFrameInfo*    frameInfo;
  2580.     GrafPtr        port;
  2581.  
  2582.     GetPort(&port);
  2583.     
  2584.     // If the facet being draw is dependent to a source frame in
  2585.     // another window, we need to access the source frame to determine
  2586.     // what size to draw the content.
  2587.  
  2588.     frameInfo = (CFrameInfo*) facet->GetFrame(ev)->GetPartInfo(ev);
  2589.     if ( frameInfo->HasSourceFrame() )
  2590.         frame = frameInfo->GetSourceFrame(ev);
  2591.     else
  2592.         frame = facet->GetFrame(ev);
  2593.  
  2594.     // Get the facet's canvas so shapes are returned in the correct
  2595.     // coordinate system.
  2596.     ODCanvas* biasCanvas = facet->GetCanvas(ev);
  2597.  
  2598.     // Calculate font height for drawing.
  2599.     TempODShape frameShape = frame->AcquireFrameShape(ev, biasCanvas);
  2600.     frameRgn = frameShape->GetQDRegion(ev);
  2601.     frameHeight = (**frameRgn).rgnBBox.bottom - (**frameRgn).rgnBBox.top;
  2602.     frameWidth = (**frameRgn).rgnBBox.right - (**frameRgn).rgnBBox.left;
  2603.  
  2604.     // Save off port chararcteristics so we can restore it later.
  2605.     ODUShort size = port->txSize;
  2606.     ODUShort font = port->txFont;
  2607.     Style face = port->txFace;
  2608.  
  2609.     // Set the font size to almost fill the frame.
  2610.     TextSize((ODUShort)(frameHeight * 0.8));
  2611.     // Use the default Application font for this script system.
  2612.     TextFont(1);
  2613.     TextFace(bold + condense);
  2614.         
  2615.     GetFontInfo(&finfo);
  2616.     
  2617.     ODSLong rfRef;
  2618.     rfRef = BeginUsingLibraryResources();
  2619.     {
  2620.         PenState penState;
  2621.         GetPenState(&penState);        
  2622.         PenNormal();        
  2623.  
  2624.         RGBColor foreState, backState;
  2625.         GetForeColor(&foreState);
  2626.         GetBackColor(&backState);
  2627.         ForeColor(blackColor);
  2628.         BackColor(whiteColor);
  2629.             
  2630.         EraseRect(&port->portRect);
  2631.  
  2632.         GetIndString(defaultString, kMenuStringResID, kDefaultContent1ID);
  2633.         MoveTo((frameWidth / 2) - (StringWidth(defaultString) / 2),
  2634.                     frameHeight - (finfo.descent - 2));
  2635.         DrawString(defaultString);
  2636.         
  2637.         // If the part is selected, fill the background with
  2638.         // the highlight color.
  2639.         if ( facet->GetHighlight(ev) == kODFullHighlight )
  2640.         {
  2641.             UInt8 mode = LMGetHiliteMode();
  2642.             BitClr(&mode,pHiliteBit);
  2643.             LMSetHiliteMode(mode);
  2644.             InvertRect(&port->portRect);
  2645.         }
  2646.         
  2647.         TextMode(srcXor);
  2648.         TextSize(24);
  2649.         TextFace(bold + extend);
  2650.  
  2651.         GetIndString(defaultString, kMenuStringResID, kDefaultContent2ID);
  2652.         MoveTo((frameWidth / 2) - (StringWidth(defaultString) / 2),
  2653.                     (frameHeight / 2) + 6);
  2654.         DrawString(defaultString);
  2655.         
  2656.         SetPenState(&penState);
  2657.         RGBForeColor(&foreState);
  2658.         RGBBackColor(&backState);
  2659.     }
  2660.     EndUsingLibraryResources(rfRef);
  2661.  
  2662.  
  2663.     // Restore port chararcteristics.
  2664.     SetPort(port);
  2665.     port->txSize = size;
  2666.     port->txFont = font;
  2667.     port->txFace = face;
  2668. */
  2669.  
  2670.     tsmDraw(ev, &fTERec, facet);    //ForTSMTE
  2671. }
  2672.  
  2673. //------------------------------------------------------------------------------
  2674. // Method:        DrawIconView
  2675. // Origin:        SamplePart
  2676. //
  2677. // Description:    This method is called by the part when the frame being
  2678. //                drawn is in "standard icon" view.
  2679. //
  2680. //                The part uses the Icon Utilities toolbox manager to
  2681. //                aid in drawing icons in active windows. The Guidelines
  2682. //                require a different appearance for selected icons in
  2683. //                inactive windows, which we do manually.
  2684. //------------------------------------------------------------------------------
  2685.  
  2686. void SamplePart::DrawIconView( Environment*        ev,
  2687.                                ODFacet*            facet )
  2688. {
  2689.     SOM_Trace("SamplePart","DrawIconView");
  2690.  
  2691.     Rect                iconRect;
  2692.     IconTransformType     transformType = ttNone;
  2693.     CFrameInfo*            frameInfo;
  2694.     ODFrame*            frame; 
  2695.     ODTypeToken            viewType;
  2696.     
  2697.     frame        = facet->GetFrame(ev);
  2698.     viewType    = frame->GetViewType(ev);
  2699.     frameInfo     = (CFrameInfo*) frame->GetPartInfo(ev);
  2700.     
  2701.     // Check to see if the facet is selected
  2702.     if ( facet->GetHighlight(ev) == kODFullHighlight )
  2703.         transformType = ttSelected;
  2704.     
  2705.     // Check to see if the frame has been opened into a part window.
  2706.     TempODWindow window = frameInfo->AcquirePartWindow(ev);
  2707.     if ( window && window->IsShown(ev) )
  2708.         transformType |= ttOpen;
  2709.     
  2710.     // Draw the icon.
  2711.     if ( viewType == gGlobals->fLargeIconView )
  2712.         SetRect(&iconRect, 0, 0, kODLargeIconSize, kODLargeIconSize);
  2713.     else // ( viewType == gGlobals->fSmallIconView )
  2714.         SetRect(&iconRect, 0, 0, kODSmallIconSize, kODSmallIconSize);
  2715.  
  2716.     CUsingLibraryResources res;
  2717.     PlotIconID(&iconRect, atAbsoluteCenter, transformType, kBaseResourceID);
  2718. }
  2719.  
  2720. //------------------------------------------------------------------------------
  2721. // Method:        DrawThumbnailView
  2722. // Origin:        SamplePart
  2723. //
  2724. // Description:    This method is called by the part when the frame being
  2725. //                drawn is in "thumbnail" view.
  2726. //
  2727. //                The part uses a picture for its thumbnail view because
  2728. //                it has no intrinsic content. A picture resource is
  2729. //                probably not sufficient for parts with real content.
  2730. //------------------------------------------------------------------------------
  2731.  
  2732. void SamplePart::DrawThumbnailView( Environment*    ev,
  2733.                                     ODFacet*        facet )
  2734. {
  2735.     SOM_Trace("SamplePart","DrawThumbnailView");
  2736.     
  2737.     // Create or retrieve a cached thumbnail picture.
  2738.     PicHandle thumbnail = this->GenerateThumbnail(ev, facet->GetFrame(ev));
  2739.     
  2740.     Rect bounds = (**thumbnail).picFrame;
  2741.     DrawPicture(thumbnail, &bounds);
  2742. }
  2743.  
  2744. //------------------------------------------------------------------------------
  2745. // Method:        GenerateThumbnail
  2746. // Origin:        SamplePart
  2747. //
  2748. // Description:    This method is called by the part to generate a thumbnail view
  2749. //                from the current content.
  2750. //
  2751. //                The part has no content, so we merely load a picture.
  2752. //------------------------------------------------------------------------------
  2753.  
  2754. PicHandle SamplePart::GenerateThumbnail( Environment*    ev,
  2755.                                          ODFrame*        frame )
  2756. {
  2757.     SOM_Trace("SamplePart","GenerateThumbnail");
  2758.     
  2759.     if ( gGlobals->fThumbnail == kODNULL )
  2760.     {
  2761.         // In cases where a part has been instantiated from scratch and has no
  2762.         // content (yet), it is appropriate to display a PICT or some graphic
  2763.         // in place of a "real" thumbnail.
  2764.         
  2765.         LoadThumbnail(ev, &gGlobals->fThumbnail);
  2766.     
  2767.         // If we were unable to load the PICT resource for whatever reason
  2768.         // we will default back to a "frame" view and throw the Resource
  2769.         // Manager error as an exception.
  2770.         if ( gGlobals->fThumbnail == kODNULL )
  2771.         {
  2772.             frame->ChangeViewType(ev, gGlobals->fFrameView);
  2773.             
  2774.             // There is a bug in ResError, when resources are not found,
  2775.             // which may cause noErr to be returned. If that is the case,
  2776.             // we throw resNotFound.
  2777.             THROW_IF_ERROR((ODError)ResError());
  2778.             THROW(resNotFound);
  2779.         }
  2780.     }
  2781.         
  2782.     return (PicHandle)gGlobals->fThumbnail;
  2783. }
  2784.  
  2785. //------------------------------------------------------------------------------
  2786. // Method:        GeometryChanged
  2787. // Origin:        ODPart
  2788. //
  2789. // Description:    This method is called when the ExternalTransform or
  2790. //                ClipShape of a facet on one this part's display frames
  2791. //                changes.
  2792. //------------------------------------------------------------------------------
  2793.  
  2794. void SamplePart::GeometryChanged( Environment*    ev,
  2795.                                   ODFacet*        facet,
  2796.                                   ODBoolean        clipShapeChanged,
  2797.                                   ODBoolean        /*externalTransformChanged*/ )
  2798. {
  2799.     SOM_Trace("SamplePart","GeometryChanged");
  2800.  
  2801.     // If clipping changed on the root frame, it means the root frame
  2802.     // shaped changed (the window was resized). OpenDoc does not invalidate
  2803.     // the area, so we must.
  2804.     if ( clipShapeChanged && facet->GetFrame(ev)->IsRoot(ev) )
  2805.         facet->Invalidate(ev, kODNULL, kODNULL);
  2806. }
  2807.  
  2808. //------------------------------------------------------------------------------
  2809. // Method:        HighlightChanged
  2810. // Origin:        ODPart
  2811. //
  2812. // Description:    This method is called when a facet....
  2813. //------------------------------------------------------------------------------
  2814.  
  2815. void SamplePart::HighlightChanged(Environment* ev, ODFacet* facet)
  2816. {
  2817.     ODFrame* frame = facet->GetFrame(ev);
  2818.     
  2819.     // The frame view has no "special" drawing characteristics
  2820.     // when opened or selected, so we don't need to update our
  2821.     // content.
  2822.     
  2823.     if ( frame->GetViewType(ev) != gGlobals->fFrameView )
  2824.         frame->Invalidate(ev, kODNULL, kODNULL);
  2825. }
  2826.  
  2827. //==============================================================================
  2828. #pragma mark    • Activation •
  2829. //==============================================================================
  2830.  
  2831. //------------------------------------------------------------------------------
  2832. // Method:        BeginRelinquishFocus
  2833. // Origin:        ODPart
  2834. //
  2835. // Description:    This method is called when another part (or possibly
  2836. //                ourself) is requesting a focus for one of its display
  2837. //                frames. Returning true means we are willing to give
  2838. //                up the requested focus.
  2839. //
  2840. //                The part willingly gives up any focus unless it is the
  2841. //                modal focus which we don't want to give up until we
  2842. //                are completely done displaying a modal dialog.
  2843. //------------------------------------------------------------------------------
  2844.  
  2845. ODBoolean SamplePart::BeginRelinquishFocus( Environment*    ev,
  2846.                                             ODTypeToken        focus,
  2847.                                             ODFrame*        /*ownerFrame*/,
  2848.                                             ODFrame*        proposedFrame )
  2849. {
  2850.     SOM_Trace("SamplePart","BeginRelinquishFocus");
  2851.  
  2852.     ODBoolean willRelinquish = kODTrue;
  2853.  
  2854.     // Another part is trying to put up a Modal dialog while we
  2855.     // are currently displaying ours. Deny the request.
  2856.     if ( focus == gGlobals->fModalFocus )
  2857.     {
  2858.         TempODPart proposedPart = ODAcquirePart(ev,proposedFrame);
  2859.         if ( ODObjectsAreEqual(ev, proposedPart, fSelf) == kODFalse )
  2860.             willRelinquish = kODFalse;
  2861.     }
  2862.                 
  2863.     return willRelinquish;
  2864. }
  2865.  
  2866. //------------------------------------------------------------------------------
  2867. // Method:        CommitRelinquishFocus
  2868. // Origin:        ODPart
  2869. //
  2870. // Description:    This method is called when it is actually time to give
  2871. //                up a focus that had been requested by another part (or
  2872. //                possibly ourself).
  2873. //
  2874. //                The part calls its FocusLost method to handle the 
  2875. //                "reliquishing" of the particular focus.
  2876. //------------------------------------------------------------------------------
  2877.  
  2878. void SamplePart::CommitRelinquishFocus( Environment*    ev,
  2879.                                         ODTypeToken        focus,
  2880.                                         ODFrame*        ownerFrame,
  2881.                                         ODFrame*        /*proposedFrame*/ )
  2882. {
  2883.     SOM_Trace("SamplePart","CommitRelinquishFocus");
  2884.  
  2885.     // We agreed to give up our FocusSet and now we are being asked to
  2886.     // do so.
  2887.     this->FocusLost(ev, focus, ownerFrame);
  2888. }
  2889.  
  2890. //------------------------------------------------------------------------------
  2891. // Method:        AbortRelinquishFocus
  2892. // Origin:        ODPart
  2893. //
  2894. // Description:    This method is called when another part (or possibly
  2895. //                ourself) requested a focus for one of its display
  2896. //                frames, but we returned kODFalse from
  2897. //                BeginRelinqishFocus for one, or all, of the requested
  2898. //                focus. At this point, we are being told to resume
  2899. //                ownership of the focus.
  2900. //------------------------------------------------------------------------------
  2901.  
  2902. void SamplePart::AbortRelinquishFocus( Environment*        ev,
  2903.                                        ODTypeToken        /*focus*/,
  2904.                                        ODFrame*            /*ownerFrame*/,
  2905.                                        ODFrame*            /*proposedFrame*/ )
  2906. {
  2907.     SOM_Trace("SamplePart","AbortRelinquishFocus");
  2908.  
  2909.     // Some parts may have suspended some events in the BeginRelinquishFocus
  2910.     // method. If so, they would resume those events here.
  2911. }
  2912.  
  2913. //------------------------------------------------------------------------------
  2914. // Method:        FocusAcquired
  2915. // Origin:        ODPart
  2916. //
  2917. // Description:    This method is called when the Arbitrator has
  2918. //                registered us as the "owner" of the particular focus.
  2919. //                This can occur if we are explicitly assigned a focus, or if a
  2920. //                focus is transfered to one of the part's display frames.
  2921. //
  2922. //                The part will request its complete focus set to become "active".
  2923. //                If the part is successful, we notify ourself to become active.
  2924. //------------------------------------------------------------------------------
  2925.  
  2926. void SamplePart::FocusAcquired( Environment*    ev,
  2927.                                 ODTypeToken        focus,
  2928.                                 ODFrame*        ownerFrame )
  2929. {
  2930.     SOM_Trace("SamplePart","FocusAcquired");
  2931.  
  2932.     ODArbitrator* arbitrator =  ODGetSession(ev,fSelf)->GetArbitrator(ev);
  2933.  
  2934.     if ( arbitrator->RequestFocusSet(ev, gGlobals->fUIFocusSet, ownerFrame) )
  2935.     {
  2936.         this->PartActivated(ev, ownerFrame);
  2937.     }
  2938. }
  2939.  
  2940. //------------------------------------------------------------------------------
  2941. // Method:        FocusLost
  2942. // Origin:        ODPart
  2943. //
  2944. // Description:    This method is called when the Arbitrator has
  2945. //                unregistered us as the "owner" of the particular
  2946. //                focus.
  2947. //
  2948. //                The part unmarks the active frame if the selection
  2949. //                focus is lost.
  2950. //------------------------------------------------------------------------------
  2951.  
  2952. void SamplePart::FocusLost( Environment*    ev,
  2953.                             ODTypeToken        focus,
  2954.                             ODFrame*        ownerFrame )
  2955. {
  2956.     SOM_Trace("SamplePart","FocusLost");
  2957.  
  2958.     if ( focus == gGlobals->fSelectionFocus )
  2959.     {
  2960.         CFrameInfo* frameInfo = (CFrameInfo*) ownerFrame->GetPartInfo(ev);
  2961.  
  2962.         //ForTSMTE
  2963.         tsmClose(ev, &fTERec, ownerFrame);
  2964. //        ODGetSession(ev,fSelf)->GetDispatcher(ev)->UnregisterIdle(ev, fSelf, ownerFrame);    
  2965.         
  2966.         frameInfo->SetFrameActive(kODFalse);
  2967.     }
  2968. }
  2969.  
  2970. //------------------------------------------------------------------------------
  2971. // Method:        RelinquishAllFoci
  2972. // Origin:        SamplePart
  2973. //
  2974. // Description:    This method is called when a frame is going away. The method
  2975. //                relinquishes all foci the frame owns.
  2976. //------------------------------------------------------------------------------
  2977.  
  2978. void SamplePart::RelinquishAllFoci( Environment*    ev,
  2979.                                     ODFrame*        frame )
  2980. {
  2981.     SOM_Trace("SamplePart","RelinquishAllFoci");
  2982.  
  2983.     ODArbitrator* arbitrator = ODGetSession(ev,fSelf)->GetArbitrator(ev);
  2984.     
  2985.     TRY
  2986.         TempODFrame focusFrame = arbitrator->AcquireFocusOwner(ev, gGlobals->fSelectionFocus);
  2987.         if ( ODObjectsAreEqual(ev, focusFrame, frame) )
  2988.         {
  2989.             arbitrator->RelinquishFocus(ev, gGlobals->fSelectionFocus, frame);
  2990.             this->FocusLost(ev, gGlobals->fSelectionFocus, frame);
  2991.         }
  2992.     CATCH_ALL
  2993.     ENDTRY
  2994.  
  2995.     TRY
  2996.         TempODFrame focusFrame = arbitrator->AcquireFocusOwner(ev, gGlobals->fMenuFocus);
  2997.         if ( ODObjectsAreEqual(ev, focusFrame, frame) )
  2998.         {
  2999.             arbitrator->RelinquishFocus(ev, gGlobals->fMenuFocus, frame);
  3000.             this->FocusLost(ev, gGlobals->fMenuFocus, frame);
  3001.         }
  3002.     CATCH_ALL
  3003.     ENDTRY
  3004. }
  3005.  
  3006. //------------------------------------------------------------------------------
  3007. // Method:        PartActivated
  3008. // Origin:        SamplePart
  3009. //
  3010. // Description:    This method is called when the part has successfully acquired
  3011. //                the set of foci which allow it to "run".
  3012. //------------------------------------------------------------------------------
  3013.  
  3014. void SamplePart::PartActivated( Environment*    ev,
  3015.                                 ODFrame*        frame )
  3016. {
  3017.     SOM_Trace("SamplePart","PartActivated");
  3018.     
  3019.     // We are required to re-validate the menubar before displaying it because
  3020.     // any part can/could swap the base menubar at any time.
  3021.     if ( gGlobals->fMenuBar->IsValid(ev) == kODFalse )
  3022.     {
  3023.         ODFinalReleaseObject(ev, gGlobals->fMenuBar);
  3024.         gGlobals->fMenuBar = ODGetSession(ev,fSelf)->GetWindowState(ev)->CopyBaseMenuBar(ev);
  3025.         
  3026.         // After copying the "new" base menu bar, don't forget to re-install
  3027.         // your part's menus.
  3028.     }
  3029.         
  3030.     // Display our menu bar.
  3031.     gGlobals->fMenuBar->Display(ev);
  3032.     
  3033.     // And set our "active" state.
  3034.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3035.     frameInfo->SetFrameActive(kODTrue);
  3036.  
  3037.     //ForTSMTE
  3038.     tsmOpen(ev, &fTERec, frame);
  3039. //    ODGetSession(ev,fSelf)->GetDispatcher(ev)->RegisterIdle(ev, fSelf, frame, TEIDLETICKS);    
  3040. }
  3041.  
  3042. //------------------------------------------------------------------------------
  3043. // Method:        ActivateFrame
  3044. // Origin:        SamplePart
  3045. //
  3046. // Description:    This method is called by the part when a kODEvtMouseUp
  3047. //                occurs in an inactive frame in an active window, and
  3048. //                when an OpenDoc document comes forward.
  3049. //
  3050. //                The part activates the frame by requesting the
  3051. //                UIFocusSet (created in Initialize) and by calling
  3052. //                FocusAcquired if we were successful. The method
  3053. //                returns true if no problems were encountered as a
  3054. //                signal to the caller that the frame is now "active".
  3055. //------------------------------------------------------------------------------
  3056.  
  3057. ODBoolean SamplePart::ActivateFrame( Environment*    ev,
  3058.                                      ODFrame*        frame )
  3059. {
  3060.     SOM_Trace("SamplePart","ActivateFrame");
  3061.  
  3062.     ODBoolean activated = kODFalse;
  3063.  
  3064.     // Request the set of foci necessary to become active.
  3065.     if ( ODGetSession(ev,fSelf)->GetArbitrator(ev)
  3066.             ->RequestFocusSet(ev, gGlobals->fUIFocusSet, frame) )
  3067.     {
  3068.         // Activate the part.
  3069.         this->PartActivated(ev, frame);
  3070.         // We were able to become active.
  3071.         activated = kODTrue;
  3072.     }
  3073.     
  3074.     // Let our caller know we succeded or failed.
  3075.     return activated;
  3076. }
  3077.  
  3078. //------------------------------------------------------------------------------
  3079. // Method:        WindowActivating
  3080. // Origin:        SamplePart
  3081. //
  3082. // Description:    This method is called by the part when a window activation
  3083. //                event (kODEvtActivate) occurs.
  3084. //
  3085. //                The part remembers the frame's active state and restores it when
  3086. //                events come in. If the frame is active and the window is being
  3087. //                sent into the background, remember to reactivate the part when
  3088. //                the window is reactivated.
  3089. //------------------------------------------------------------------------------
  3090.  
  3091. void SamplePart::WindowActivating( Environment*        ev,
  3092.                                    ODFrame*            frame,
  3093.                                    ODBoolean        activating )
  3094. {
  3095.     SOM_Trace("SamplePart","WindowActivating");
  3096.  
  3097.     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3098.     
  3099.     // The window is being activated and we had the selection focus when
  3100.     // the window was deactivated, so activate ourself.
  3101.     if ( activating && frameInfo->FrameNeedsReactivating() )
  3102.     {
  3103.         this->ActivateFrame(ev, frame);
  3104.         frameInfo->SetFrameReactivate(kODFalse);
  3105.     }
  3106.     // The window is being deactivated and we are the active part.
  3107.     // Give up our foci and remind ourselves that we need to request
  3108.     // the focus when the window is reactivated.
  3109.     else if ( !activating && frameInfo->IsFrameActive() )
  3110.     {
  3111.         //ForTSMTE
  3112.         tsmClose(ev, &fTERec, frame);
  3113. //        ODGetSession(ev,fSelf)->GetDispatcher(ev)->UnregisterIdle(ev, fSelf, frame);    
  3114.  
  3115.         frameInfo->SetFrameReactivate(kODTrue);
  3116.     }
  3117. }
  3118.  
  3119. //==============================================================================
  3120. #pragma mark    • Event Handling •
  3121. //==============================================================================
  3122.  
  3123. //------------------------------------------------------------------------------
  3124. // Method:        HandleEvent
  3125. // Origin:        ODPart
  3126. //
  3127. // Description:    The method is called when an event, which falls into
  3128. //                the category of an owned focus, occurs. The two
  3129. //                exceptions to this are "mouse movement" events and 
  3130. //                embedded frame events, which can occur when a part
  3131. //                owns no foci.
  3132. //
  3133. //                The part returns true if the event was handled.
  3134. //------------------------------------------------------------------------------
  3135.  
  3136.  
  3137. ODBoolean SamplePart::HandleEvent( Environment*        ev,
  3138.                                    ODEventData*        event,
  3139.                                    ODFrame*            frame,
  3140.                                    ODFacet*            facet,
  3141.                                    ODEventInfo*        eventInfo )
  3142. {
  3143.     SOM_Trace("SamplePart","HandleEvent");
  3144.  
  3145.     ODBoolean    eventHandled = kODFalse;
  3146.  
  3147.     // Event handling is basically the same as standard Macintosh applications,
  3148.     // except that the events have been renamed for cross-platform compatability.
  3149.     
  3150.     switch ( event->what )
  3151.     {
  3152.         case kODEvtMouseDown:
  3153.         case kODEvtMouseUp:
  3154.             eventHandled = this->HandleMouseEvent(ev, event, facet, eventInfo);
  3155.             break;
  3156.             
  3157.         case kODEvtMenu:
  3158.             eventHandled = this->HandleMenuEvent(ev, event, frame);
  3159.             break;
  3160.  
  3161.         case kODEvtActivate:
  3162.             // We are being notified that a window we are displayed in has
  3163.             // just been de/activated (un/hilighted).
  3164.             this->WindowActivating(ev, frame, (event->modifiers & activeFlag));
  3165.             eventHandled = kODTrue;
  3166.             break;
  3167.     
  3168.         case kODEvtMouseEnter:
  3169.         case kODEvtMouseLeave:
  3170.             SetCursor(&ODQDGlobals.arrow);
  3171.             eventHandled = kODTrue;
  3172.             break;
  3173.  
  3174.         case kODEvtMouseWithin:
  3175.             eventHandled = kODTrue;
  3176.             break;
  3177.  
  3178.         //ForTSMTE
  3179.         case kODEvtKeyDown:
  3180.         case kODEvtAutoKey:
  3181.             tsmKey(ev, &fTERec, frame, event);
  3182.             eventHandled = kODTrue;
  3183.             break;
  3184.  
  3185.         //ForTSMTE
  3186.         case kODEvtNull:
  3187.             tsmIdle(ev, &fTERec);
  3188.             eventHandled = kODTrue;
  3189.             break;
  3190.             
  3191.         // Other events a part might handle
  3192. //        case kODEvtNull:
  3193.         case kODEvtMouseDownEmbedded:
  3194.         case kODEvtMouseUpEmbedded:
  3195.         case kODEvtMouseDownBorder:
  3196.         case kODEvtMouseUpBorder:
  3197.         case kODEvtWindow:
  3198. //        case kODEvtKeyDown:
  3199. //        case kODEvtKeyUp:
  3200. //        case kODEvtAutoKey:
  3201.         case kODEvtOS:
  3202.         case kODEvtDisk:
  3203.         
  3204.         default:
  3205.             break;
  3206.     }
  3207.  
  3208.     return eventHandled;
  3209. }
  3210.  
  3211. //------------------------------------------------------------------------------
  3212. // Method:        AdjustMenus
  3213. // Origin:        ODPart
  3214. //
  3215. // Description:    This method is called when a kODEvtMouseDown event occurs in the
  3216. //                menubar and the part owns the "menu" focus, or when the part is
  3217. //                root part of a document.
  3218. //
  3219. //                The part first verifies that the base menubar has not been
  3220. //                modified, then enables the menu items and changes their names
  3221. //                where appropriate (eg. About SamplePart...).
  3222. //------------------------------------------------------------------------------
  3223.  
  3224. void SamplePart::AdjustMenus( Environment*    ev,
  3225.                               ODFrame*        frame )
  3226. {
  3227.     SOM_Trace("SamplePart","AdjustMenus");
  3228.  
  3229.     // The menubar object always calls the root part's AdjustMenus method before
  3230.     // calling the menu focus owner's. Because of this, we need to validate the
  3231.     // menubar in the case where we are the root part.
  3232.     if ( frame->IsRoot(ev) )
  3233.     {
  3234.         // We are required to re-validate the menubar before displaying it because
  3235.         // any part can/could swap the base menubar at any time.
  3236.         if ( gGlobals->fMenuBar->IsValid(ev) == kODFalse )
  3237.         {
  3238.             ODFinalReleaseObject(ev, gGlobals->fMenuBar);
  3239.             gGlobals->fMenuBar = ODGetSession(ev,fSelf)->GetWindowState(ev)->CopyBaseMenuBar(ev);
  3240.             
  3241.             // After copying the "new" base menu bar, don't forget to re-install
  3242.             // your part's menus.
  3243.         }
  3244.     }        
  3245.  
  3246.     // Enable the "View As Window" command always.
  3247.     gGlobals->fMenuBar->EnableCommand(ev, kODCommandViewAsWin, !frame->IsRoot(ev));
  3248.  
  3249.     // Disable the clipboard commands always
  3250.     gGlobals->fMenuBar->EnableCommand(ev, kODCommandCut,     kODFalse);
  3251.     gGlobals->fMenuBar->EnableCommand(ev, kODCommandPaste,   kODFalse);
  3252.     gGlobals->fMenuBar->EnableCommand(ev, kODCommandPasteAs, kODFalse);
  3253.     gGlobals->fMenuBar->EnableCommand(ev, kODCommandClear,   kODFalse);
  3254.     
  3255.     TRY
  3256.         ODArbitrator* arbitrator = ODGetSession(ev,fSelf)->GetArbitrator(ev);
  3257.         TempODFrame menuOwner = arbitrator->AcquireFocusOwner(ev, gGlobals->fMenuFocus);
  3258.     
  3259.         // There is no need to load a resource, create an ODIText object, set the menubar,
  3260.         // and cleanup, if we don't own the menu focus.
  3261.         if ( ODObjectsAreEqual(ev, frame, menuOwner) )
  3262.         {
  3263.             Str63 text;
  3264.             
  3265.             // Get the "about" string from our library's resources.
  3266.             // (note: ODGetIndString focuses the resource fork for us)
  3267.             ODGetIndString(text, kMenuStringResID, kAboutTextID);
  3268.             // Create an IText object to pass into the menubar.
  3269.             TempODIText    menuItem(CreateIText(gGlobals->fEditorsScript, gGlobals->fEditorsLanguage,
  3270.                                     (StringPtr)&text));
  3271.             // Change the "About" menu item text for our part.
  3272.             gGlobals->fMenuBar->SetItemString(ev, kODCommandAbout, menuItem);
  3273.         }
  3274.     CATCH_ALL
  3275.         // consume exception
  3276.     ENDTRY
  3277. }
  3278.  
  3279. //------------------------------------------------------------------------------
  3280. // Method:        HandleMenuEvent
  3281. // Origin:        SamplePart
  3282. //
  3283. // Description:    This method is called by the part when a menu event is
  3284. //                received.
  3285. //
  3286. //                Using the menu bar object, we determine what the menu
  3287. //                command is, and call the appropriate method to handle
  3288. //                it.
  3289. //------------------------------------------------------------------------------
  3290.  
  3291. ODBoolean SamplePart::HandleMenuEvent( Environment*        ev,
  3292.                                        ODEventData*        event,
  3293.                                        ODFrame*            frame )
  3294. {
  3295.     SOM_Trace("SamplePart","HandleMenuEvent");
  3296.  
  3297.     ODULong        menuResult    = event->message;
  3298.     ODUShort    menu        = HiWord(menuResult);
  3299.     ODUShort    item        = LoWord(menuResult);
  3300.  
  3301.     switch ( gGlobals->fMenuBar->GetCommand(ev, menu, item) )
  3302.     {
  3303.         case kODCommandAbout:    
  3304.             this->DoDialogBox(ev, frame, kAboutBoxID);
  3305.             break;
  3306.  
  3307.         case kODCommandViewAsWin:
  3308.             this->Open(ev, frame);
  3309.             break;
  3310.  
  3311.         // Other commands a part might handle
  3312.         case kODCommandOpen:
  3313.         case kODCommandInsert:
  3314.         case kODCommandPageSetup:
  3315.         case kODCommandPrint:
  3316.         case kODCommandUndo:
  3317.         case kODCommandRedo:
  3318.         case kODCommandCut:
  3319.         case kODCommandCopy:
  3320.         case kODCommandPaste:
  3321.         case kODCommandPasteAs:
  3322.         case kODCommandClear:
  3323.         case kODCommandSelectAll:
  3324.         case kODCommandGetPartInfo:
  3325.         case kODCommandPreferences:
  3326.  
  3327.         default:
  3328.             return kODFalse;
  3329.     }
  3330.         
  3331.     return kODTrue;
  3332. }
  3333.  
  3334. //------------------------------------------------------------------------------
  3335. // Method:        HandleMouseEvent
  3336. // Origin:        SamplePart
  3337. //
  3338. // Description:    This method is called by the part when a mouse event
  3339. //                is recieved.
  3340. //
  3341. //                A typical part would determine the event type(up/down)
  3342. //                and respond appropriately, but we have no "real"
  3343. //                content model, so we activate the part as appropriate
  3344. //                and call a generic method to handle the event.
  3345. //
  3346. // Remember:    When a frame is inactive, the first mouse up event
  3347. //                should activate it; inactive frames do not recieve
  3348. //                kODEvtMouseDown events.
  3349. //------------------------------------------------------------------------------
  3350.  
  3351. ODBoolean SamplePart::HandleMouseEvent( Environment*    ev,
  3352.                                         ODEventData*    event,
  3353.                                         ODFacet*        facet,
  3354.                                         ODEventInfo*    eventInfo )
  3355. {
  3356.     SOM_Trace("SamplePart","HandleMouseEvent");
  3357.  
  3358.     // If the facet parameter is invalid, the mouse up occurred outside the
  3359.     // bounds of a Modal window, otherwise it should be treated normally.
  3360.     
  3361.     if ( facet != kODNULL )
  3362.     {
  3363.         if ( event->what == kODEvtMouseUp )
  3364.         {
  3365.             ODWindow* window = facet->GetWindow(ev);
  3366.  
  3367.             TRY
  3368.                 // Activate inactive windows on the first mouse up event.
  3369.                 if ( !window->IsActive(ev) )
  3370.                     window->Select(ev);
  3371.                 // Activate the frame (if needed) on all subsequent mouse up events.
  3372.                 else
  3373.                 {
  3374.                     ODFrame* frame = facet->GetFrame(ev);
  3375.                     
  3376.                     // Get our state information from the PartInfo of the frame.
  3377.                     CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev);
  3378.                                     
  3379.                     // If this frame is not the active one, activate it by requesting
  3380.                     // the appropriate foci.
  3381.         
  3382.                     if ( !frameInfo->IsFrameActive() )
  3383.                     {
  3384.                         if ( this->ActivateFrame(ev, frame) )
  3385.                             // Keep track of which facet was the last active for positioning
  3386.                             // child windows.
  3387.                             frameInfo->SetActiveFacet(facet);
  3388.                         else
  3389.                             // We were unable to acquire the necessary focus and activate it.
  3390.                             return kODFalse;
  3391.                     }
  3392.                 }
  3393.             CATCH_ALL
  3394.             ENDTRY
  3395.         }
  3396.         else if ( event->what == kODEvtMouseDown )                
  3397.         {
  3398.             Point where;
  3399.  
  3400.             // Get the localized mouse coordinates from the Event Info.
  3401.             where.h = FixedToInt(eventInfo->where.x);
  3402.             where.v = FixedToInt(eventInfo->where.y);
  3403.         
  3404.             // Handle the mouse down event.
  3405.             //ForTSMTE
  3406.             this->DoMouseEvent(ev, facet, &where, event); // need event record
  3407. //            this->DoMouseEvent(ev, facet, &where);
  3408.         }
  3409.     }
  3410.     else
  3411.     {
  3412.         // User clicked outside the bounds of a Modal window, though we actually
  3413.         // never display one.
  3414.         
  3415.         SysBeep(1);
  3416.     }
  3417.  
  3418.     return kODTrue;
  3419. }
  3420.  
  3421. //------------------------------------------------------------------------------
  3422. // Method:        DoMouseEvent
  3423. // Origin:        SamplePart
  3424. //
  3425. // Description:    This method is called by the part to handle mouse
  3426. //                events.
  3427. //------------------------------------------------------------------------------
  3428.  
  3429. void SamplePart::DoMouseEvent( Environment*        ev,
  3430.                                ODFacet*            facet,/*ForTSMTE/*facet*/
  3431.                                Point*            where,/*ForTSMTE/*where*/
  3432.                                ODEventData*        event)/*ForTSMTE*/
  3433. {
  3434.     SOM_Trace("SamplePart","DoMouseEvent");
  3435.     
  3436.     // If you part allows selections or a lasso tool, this is where you
  3437.     // would handle those events. This is also where you would handle
  3438.     // program controlled buttons or controls.
  3439.  
  3440.     tsmClick(ev, &fTERec, facet, where, event);    //ForTSMTE
  3441. }
  3442.  
  3443. //------------------------------------------------------------------------------
  3444. // Method:        DoDialogBox
  3445. // Origin:        SamplePart
  3446. //
  3447. // Description:    This method is called by the part when a dialog needs to be
  3448. //                displayed (eg. the About Box). If a valid error number is passed
  3449. //                in, an error dialog will be displayed.
  3450. //------------------------------------------------------------------------------
  3451.  
  3452. void SamplePart::DoDialogBox( Environment*    ev,
  3453.                               ODFrame*        frame,
  3454.                               ODSShort        dialogID,
  3455.                               ODUShort        errorNumber )
  3456. {
  3457.     SOM_Trace("SamplePart","DoDialogBox");
  3458.  
  3459.     ODFrame* focusFrame = frame;
  3460.     ODSession*    session = ODGetSession(ev,fSelf);
  3461.     
  3462.     // If the calling method does not have a frame available to it, we need to
  3463.     // locate a frame to use for requesting the modal focus. Find the first valid
  3464.     // frame in our display frames list.
  3465.     if ( focusFrame == kODNULL )
  3466.     {
  3467.         CListIterator fiter(fDisplayFrames);
  3468.         for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First();
  3469.                 fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() )
  3470.         {
  3471.             if ( proxy->FrameIsLoaded(ev) )
  3472.                 focusFrame = proxy->GetFrame(ev);
  3473.             if ( focusFrame ) break;
  3474.         }
  3475.     }
  3476.     
  3477.     // Our dialog boxes are modal so we must request the Modal focus to prevent
  3478.     // multiple modal dialogs being displayed simultaneously.
  3479.     
  3480.     TempFocus modalFocus(ev, gGlobals->fModalFocus, focusFrame);
  3481.     if ( modalFocus.Request() )
  3482.     {
  3483.         ODSShort    itemHit;
  3484.  
  3485.         // Dim the frontmost document window.
  3486.         session->GetWindowState(ev)->DeactivateFrontWindows(ev);
  3487.                 
  3488.         CUsingLibraryResources res;
  3489.  
  3490.         DialogPtr dialog = ODGetNewDialog(ev, dialogID, session, kODTrue);
  3491.             
  3492.         if ( dialog )
  3493.         {
  3494.             if ( errorNumber > 0 )
  3495.             {
  3496.                 Handle    itemHandle;
  3497.                 Rect    itemRect;
  3498.                 short    itemType;
  3499.                 Str255    errStr;
  3500.                 
  3501.                 GetIndString(errStr, kErrorStringResID, errorNumber);
  3502.                 GetDialogItem(dialog, kErrStrFieldID, &itemType, &itemHandle, &itemRect);
  3503.                 SetDialogItemText(itemHandle, errStr);
  3504.                 
  3505.                 // We don't need the cancel button for an error dialog.
  3506.                 HideDialogItem(dialog, cancel);
  3507.             }
  3508.             
  3509.             SetCursor(&ODQDGlobals.arrow);
  3510.             ShowWindow(dialog);
  3511.             ModalDialog(kODNULL, &itemHit);
  3512.             DisposeDialog(dialog);
  3513.         }
  3514.         else
  3515.         {
  3516.             // Could not load About box dialog... something is amiss.
  3517.             SysBeep(2);
  3518.         }
  3519.         
  3520.         // Hilite the frontmost document window.
  3521.         session->GetWindowState(ev)->ActivateFrontWindows(ev);
  3522.     }
  3523.     else
  3524.     {
  3525.         // If we can't get the modal focus, then another modal dialog is
  3526.         // already being displayed.
  3527.         SysBeep(2);
  3528.     }
  3529. }
  3530.  
  3531.